大多數(shù)的開(kāi)發(fā)者在使用Java或C#等基于類(lèi)的語(yǔ)言的過(guò)程中學(xué)會(huì)了面向?qū)ο缶幊獭S捎贘avaScript沒(méi)有對(duì)類(lèi)的正式支持(當(dāng)然ES2015支持了),這些開(kāi)發(fā)者在學(xué)習(xí)JavaScript時(shí)往往會(huì)迷失方向采缚。JavaScript不需要在開(kāi)頭就定義好各種類(lèi)针炉,你可以在寫(xiě)代碼過(guò)程中根據(jù)需要?jiǎng)?chuàng)建數(shù)據(jù)結(jié)構(gòu)。由於JavaScript缺少類(lèi)扳抽,也就缺少用於對(duì)類(lèi)進(jìn)行分組的包篡帕。在Java中,包和類(lèi)的名字不僅定義了對(duì)象的類(lèi)型贸呢,也在工程中列出文件和目錄的層次結(jié)構(gòu)镰烧,JavaScript編程就好像從一塊空白石板開(kāi)始:你可以在上面組織任何你想要的東西。有些開(kāi)發(fā)者選擇模仿其他語(yǔ)言的結(jié)構(gòu)楞陷,也有一下人則利用JavaScript的靈活性來(lái)創(chuàng)建一些新的東西怔鳖,對(duì)沒(méi)有掌握J(rèn)avaScript的人來(lái)說(shuō),這種選擇的自由令人崩潰固蛾,然而你一旦熟悉了它结执,你會(huì)發(fā)現(xiàn)JavaScript是一個(gè)無(wú)比靈活的語(yǔ)言,可以很輕鬆的適應(yīng)你的編程習(xí)慣艾凯。
爲(wèi)了便於開(kāi)發(fā)者的從傳統(tǒng)的面向?qū)ο笳Z(yǔ)言過(guò)渡献幔,JavaScript把對(duì)象作爲(wèi)語(yǔ)言的中心。幾乎所有JavaScript的數(shù)據(jù)要麼是一個(gè)對(duì)象要麼從對(duì)象中獲取览芳。其實(shí)就連函數(shù)在JavaScript中也視爲(wèi)對(duì)象斜姥,這使得它們成爲(wèi)了JavaScript的一等公民。
使用和理解對(duì)象是整個(gè)JavaScript的關(guān)鍵。你可以在任何時(shí)候創(chuàng)建對(duì)象铸敏,在任何時(shí)候給對(duì)象添加缚忧,刪除屬性。JavaScript對(duì)象是如此的靈活杈笔,可以創(chuàng)造出其他語(yǔ)言不具有的獨(dú)特而有趣的模式闪水。
本章致力於鑑別和使用兩種JavaScript基本數(shù)據(jù)類(lèi)型:原始類(lèi)型和引用類(lèi)型。雖然兩種都是通過(guò)對(duì)象進(jìn)行訪問(wèn)蒙具,但是理解它們行爲(wèi)之間的區(qū)別是非常重要的球榆。
1.1 什麼是類(lèi)型
JavaScript雖然沒(méi)有類(lèi)的概念,但依然存在兩種類(lèi)型:原始類(lèi)型和引用類(lèi)型禁筏。原始類(lèi)型保存爲(wèi)簡(jiǎn)單數(shù)據(jù)值持钉。引用類(lèi)型則保存爲(wèi)對(duì)象,其本質(zhì)是指向內(nèi)存位置的引用篱昔。
爲(wèi)了讓開(kāi)發(fā)者都能夠把原始類(lèi)型和引用類(lèi)型按相同的方式處理每强,JavaScript花費(fèi)了很大努力來(lái)保證語(yǔ)言的一致性。
其他編程語(yǔ)言用棧存儲(chǔ)原始類(lèi)型州刽,用堆存儲(chǔ)引用類(lèi)型空执,JavaScript則完全不同:它使用一個(gè)變量對(duì)象追蹤變量的生存期。原始值被直接保存在變量對(duì)象內(nèi)穗椅,而引用值則作爲(wèi)一個(gè)指針保證在變量對(duì)象內(nèi)辨绊,該指針指向?qū)嶋H對(duì)象在內(nèi)存在的存儲(chǔ)位置。雖然看上去原始值和引用值一樣匹表,但是它們還是有區(qū)別的门坷,本章稍後會(huì)介紹。
當(dāng)然桑孩,原始類(lèi)型和引用類(lèi)型還有其他區(qū)別拜鹤。
1.2 原始類(lèi)型
原始類(lèi)型代表照原樣保存的一些簡(jiǎn)單數(shù)據(jù),如true和25.JavaScript共有5種原始類(lèi)型流椒,如下:
boolean ? 布爾敏簿,值爲(wèi)true或false
number ? ?數(shù)字,值爲(wèi)任何整型或浮點(diǎn)數(shù)值
string ? ? ?字符串宣虾,值爲(wèi)由單引號(hào)或雙引號(hào)擴(kuò)出的單個(gè)字符或連續(xù)字符(JavaScript不區(qū)分字符類(lèi)型)
null ? ? ? ?空類(lèi)型惯裕,該原始值有且僅有一個(gè)值:null
undefined ?未定義,該原始類(lèi)型也是有且僅有一個(gè)值:undefined(undefined會(huì)被賦給一個(gè)還沒(méi)有初始化的變量)
前三種(boolean绣硝,number蜻势,string)表現(xiàn)的行爲(wèi)類(lèi)似,而後兩種(null和undefined)則有一點(diǎn)區(qū)別鹉胖,本章後面將會(huì)討論握玛。所有原始類(lèi)型的值都有字面形式够傍。字面形式是不被保存在變量種的值,如硬編碼的姓名或價(jià)格挠铲。下面是每種類(lèi)型使用字面形式的例子冕屯。
//strings
var name ="Nicholas";
var selection="a";
//number
var count=5;
var cost=1.51;
//boolean
var found=true;
//null
var object=null;
//undefined
var flag=undefined;
var ref;//assigned undefined automatically
JavaScript和許多其他語(yǔ)言一樣,原始類(lèi)型的變量直接保存原始值(而不是一個(gè)指向?qū)ο蟮闹羔槪┓髌弧.?dāng)你將原始值賦值給一個(gè)變量時(shí)安聘,該值將被賦值到變量中。也就是說(shuō)瓢棒,如果你使一個(gè)變量等於另一個(gè)變量時(shí)浴韭,每個(gè)變量有它自己的一份數(shù)據(jù)拷貝。例如脯宿,
var color1="red";
var color2=color1;
這裏念颈,color1被賦值爲(wèi)"red"。變量color2被賦予color1的值嗅绰,這樣變量color2中就保存了"red"舍肠。雖然color1和color2具有同樣的值搀继,但是兩者毫無(wú)關(guān)聯(lián)窘面,改變color1的值是不影響color2,反之亦然叽躯。這是因爲(wèi)存在兩個(gè)不同的存儲(chǔ)地址财边,每個(gè)變量擁有一個(gè)。
因爲(wèi)每個(gè)含有原始值的變量使用自己的存儲(chǔ)空間点骑,一個(gè)變量的改變不會(huì)影響到其他變量酣难。例如
var color1="red";
var color2=color1;
console.log(color1);//red
console.log(color2);//red
color1="blue";
console.log(color1);//blue
console.log(color2);//red
這段代碼中,color1被改爲(wèi)“blue黑滴,而color2還保有原來(lái)的值"red”憨募。
1.2.1 鑒別原始類(lèi)型
鑒別原始類(lèi)型的最佳方法是使用typeof操作符。它可以被用在字符串袁辈,數(shù)字菜谣,布爾和未定義類(lèi)型。下面是typeof對(duì)不同原始類(lèi)型的輸出晚缩。
console.log(typeof "nicholas"); //"string"
console.log(typeof 10);// number
console.log(typeof 5.1 ); //number
console.log(typeof true); //boolean
console.log(typeof undefined) undefined
正如我們所期望的那樣尾膊,對(duì)於字符串,typeof將返回"string"荞彼,對(duì)於數(shù)字將返回'number'(無(wú)論整型還是浮點(diǎn)型)冈敛,對(duì)於布爾類(lèi)型將返回‘boolean’,對(duì)於未定義類(lèi)型將返回'undefined'鸣皂。對(duì)於空類(lèi)型則有一些棘手抓谴。
下面那行代碼的運(yùn)行結(jié)果困擾了很多開(kāi)發(fā)者
console.log(typeof null);//object
當(dāng)你運(yùn)行typeof null時(shí)暮蹂,結(jié)果是object。但是這是為什麼呢癌压?(其實(shí)這已經(jīng)被設(shè)計(jì)和維護(hù)javascript的委員會(huì)TC39認(rèn)定是一個(gè)錯(cuò)誤椎侠。在邏輯上,你可以認(rèn)為null是一個(gè)空的對(duì)象指針措拇,所以結(jié)果為‘object’我纪,但這還是令人困惑)
判斷一個(gè)值是否為空類(lèi)型嘴賤的方法是直接和null比較,如下丐吓。
console.log(value===null) //true or false
非強(qiáng)制轉(zhuǎn)換比較:
三等號(hào)在進(jìn)行比較時(shí)不會(huì)將變量強(qiáng)制轉(zhuǎn)換為另一種類(lèi)型
1.3 引用類(lèi)型
引用類(lèi)型是指javascript中的對(duì)象浅悉,同時(shí)也是你在該語(yǔ)言中能找到的最接近類(lèi)的東西。引用值時(shí)引用類(lèi)型的實(shí)例券犁,也是對(duì)象的同義詞(本章後面將用對(duì)象指代引用值)术健。對(duì)象是屬性的無(wú)序曆表。屬性包含鍵(始終是字符串)和值粘衬。如果一個(gè)屬性的值是函數(shù)荞估,它就被稱(chēng)為方法。javascript中函數(shù)其實(shí)是引用值稚新,除了函數(shù)可以運(yùn)行以外勘伺,一個(gè)包含數(shù)組的屬性和一個(gè)包含函數(shù)的屬性沒(méi)什麼區(qū)別。
當(dāng)然褂删,在使用對(duì)象前飞醉,你必須先創(chuàng)建它們。
1.3.1 創(chuàng)建對(duì)象
有時(shí)候屯阀,把javascript對(duì)象想像成哈希表可以幫助你更好的理解對(duì)象的結(jié)構(gòu)缅帘。
javascript有好幾種方法可以創(chuàng)建對(duì)象,或者說(shuō)實(shí)例化對(duì)象难衰。第一種是使用new操作符合構(gòu)造函數(shù)钦无。構(gòu)造函數(shù)就是通過(guò)new操作符來(lái)創(chuàng)建對(duì)象的函數(shù)--任何函數(shù)都可以是構(gòu)造函數(shù)。根據(jù)命名規(guī)範(fàn)盖袭,javascript中的構(gòu)造函數(shù)用首字母大寫(xiě)來(lái)跟非構(gòu)造函數(shù)進(jìn)行區(qū)分失暂。例如下列代碼實(shí)例化一個(gè)通用對(duì)象,並將它的引用保存在object中苍凛。
var object = new Object();
因?yàn)橐妙?lèi)型不在變量中直接保存對(duì)象趣席,所以本例中的object變量實(shí)際上並不包含對(duì)象的實(shí)例,而是一個(gè)指向內(nèi)存中實(shí)際對(duì)象所在位置的指針(或者說(shuō)引用)醇蝴。這是對(duì)象和原始值之間的一個(gè)基本差別宣肚,原始值是直接保存在變量中的。
當(dāng)你將一個(gè)對(duì)象賦值給變量時(shí)悠栓,實(shí)際是賦值給這個(gè)變量一個(gè)指針霉涨。這意味著按价,將一個(gè)變量賦值給另一個(gè)變量時(shí),兩個(gè)變量各獲得了一份指針的拷貝笙瑟,指向內(nèi)存中的同一個(gè)對(duì)象楼镐。例如,
var object1=new Object();
var object2=object1;
這段代碼先用new創(chuàng)建了一個(gè)對(duì)象並將其引用保存在object1中往枷。然後將object1的值賦值給object2.兩個(gè)變量都指向第一行被創(chuàng)建的那個(gè)對(duì)象實(shí)例框产。
1.3.2 對(duì)象的引用解除
javascript語(yǔ)言有垃圾收集的功能,因此當(dāng)你使用引用類(lèi)型時(shí)無(wú)需擔(dān)心內(nèi)存分配問(wèn)題错洁。但最好在不使用對(duì)象時(shí)將其引用解除秉宿,讓垃圾收集器對(duì)那塊內(nèi)存進(jìn)行釋放。解除引用的最佳手段是將對(duì)象變量重置為null屯碴。
var object1=new Object();
//do something
object1=null;//dereference
這裏描睦,對(duì)象object1被創(chuàng)建然後使用,最後設(shè)置為null导而。當(dāng)內(nèi)存中的對(duì)象不再被引用後忱叭,垃圾收集器會(huì)把那塊內(nèi)存挪作它用(在那些使用幾百萬(wàn)對(duì)象的巨型程序裡,對(duì)象引用解除尤其重要)
1.3.3 添加刪除屬性
在javascript中今艺,對(duì)象另一個(gè)有趣的地方是你可以隨時(shí)添加和刪除其屬性韵丑。例如,
var object1=new Object();
var object2=object1;
object1.myCustomProperty="Awesome!";
console.log(object2.myCustomProperty);//"Awesome!"
這裏洼滚,object1上增加了myCustomProperty屬性埂息,值為"Awesome!”遥巴。該屬性也可以被object2訪問(wèn)到,因?yàn)閛bject1和object2指向同一個(gè)對(duì)象享幽。
除了通用對(duì)象引用類(lèi)型以外铲掐,javascript還有其他一些內(nèi)建類(lèi)型任你使用。
1.4 內(nèi)建類(lèi)型實(shí)例化
你已經(jīng)見(jiàn)過(guò)如何使用new Object()創(chuàng)建和使用通用對(duì)象值桩。Object類(lèi)型只是javascript提供的少量?jī)?nèi)建引用類(lèi)型之一摆霉。其他內(nèi)建類(lèi)型各有它們的特殊用途,可在任何時(shí)候被實(shí)例化奔坟。
這些內(nèi)建類(lèi)型如下:
Array ? 數(shù)組類(lèi)型携栋,以數(shù)字為索引的一組值的有序列表
Data ? ?日期和和時(shí)間類(lèi)型
Error ? 運(yùn)行期錯(cuò)誤類(lèi)型(還有一些更特別的錯(cuò)誤例子類(lèi)型)
Function 函數(shù)類(lèi)型
Object 通用對(duì)象類(lèi)型
RegExp 正則表達(dá)式類(lèi)型
可以用new來(lái)實(shí)例化每一個(gè)內(nèi)建引用類(lèi)型,如下:
var items =new Array();
var now =new Date();
var error =new Error("Something bad happened");
var func =new Function("console.log('Hi')");
var object=new Object();
var re=new RegExp("\\d+");
1.4.1 字面形式
內(nèi)建引用類(lèi)型有字面形式咳秉。字面形式允許你在不需要使用new操作符合構(gòu)造函數(shù)顯示創(chuàng)建對(duì)象的情況下生成引用值(你曾在本章前面見(jiàn)過(guò)原始類(lèi)型的字面形式婉支,包括字符串,數(shù)字澜建,布爾向挖,空類(lèi)型和為定義)蝌以。
1.4.2 對(duì)象和數(shù)組字面形式
要用對(duì)象字面形式創(chuàng)建對(duì)象,可以在大括號(hào)內(nèi)定義一個(gè)新對(duì)象及其屬性何之。屬性的組成包括一個(gè)表示符或字符串跟畅,一個(gè)冒號(hào)以及一個(gè)值。多個(gè)屬性值之間用逗號(hào)分割溶推。例如
var book ={
name:"The Principles of Object-Oriented JavaScript",
year:2014
};
屬性名字也可以用字符串表示徊件,特別是當(dāng)你希望名字中包含空格或其他特殊字符時(shí)。
var book={
"name":"The Principles of Object-Oriented JavaScript",
"year":2014
};
本例等價(jià)於前一個(gè)例子蒜危,僅在語(yǔ)法上有區(qū)別庇忌,下面是另一個(gè)等價(jià)寫(xiě)法。
var book=new Object();
book.name="The Principles of Object-Oriented JavaScript";
book.year=2014;
雖然3例的結(jié)果是一致的:一個(gè)具有兩個(gè)屬性的對(duì)象舰褪。寫(xiě)法完全取決於你皆疹。
注意:雖然使用字面形式並沒(méi)有調(diào)用new Object(),但是javascript引擎背後做的工作和new Object()一樣占拍,除了密友調(diào)用構(gòu)造函數(shù)略就,其他引用 類(lèi)型的字面形式也是如此。
定義數(shù)組的字面形式是在中括號(hào)內(nèi)使用逗號(hào)區(qū)分的人士數(shù)量的值晃酒。例如:
var colors=["red","blue","green"];
console.log(colors[0]);//''red"
這段代碼等價(jià)於
var colors=new Array("red","blue","green");
console.log(colors[0]);
1.4.3 函數(shù)字面形式
基本上都要用字面形式來(lái)定義函數(shù)表牢。考慮到在可維護(hù)性贝次,易讀性和調(diào)試上的巨大挑戰(zhàn)崔兴,通常不會(huì)有人使用函數(shù)的構(gòu)造函數(shù),因此很少看到用字符串表示的代碼而不是實(shí)際的代碼蛔翅。
使用字面形式創(chuàng)建函數(shù)更方便也更不容易出錯(cuò)敲茄。如下例:
function reflect(value){
return value;
}
//is the same
var reflect=new Function("value","return value;");
1.4.4正則表達(dá)式字面形式
javascript允許使用字面形式而不是RexExp構(gòu)造函數(shù)定義正則表達(dá)式。它們看上去類(lèi)似Perl中的正則表達(dá)式山析;模式被包含在兩個(gè)“/”之間堰燎,第二個(gè)“/”後是由單字符表示的額外的選項(xiàng)。
var number =/\d+/g;
// is the same as
var numbers = new RegExp("\\d+","g");
使用字面形式比較方便的一個(gè)原因是你不需要擔(dān)心字符串中的轉(zhuǎn)億字符笋轨。如果使用RegExp構(gòu)造函數(shù)秆剪,傳入模式的參數(shù)時(shí)一個(gè)字符串,你需要對(duì)任何反斜槓進(jìn)行轉(zhuǎn)義爵政。在javascript中仅讽,除非需要通過(guò)一個(gè)或多個(gè)字符串動(dòng)態(tài)構(gòu)造函數(shù)表達(dá)式,否則都建議使用字面形式而不是構(gòu)造函數(shù)钾挟。
總之洁灵,除了函數(shù),對(duì)內(nèi)建類(lèi)型沒(méi)有什麼正確或錯(cuò)誤的實(shí)例化方法等龙。很多開(kāi)發(fā)者喜歡字面形式处渣,另一些則喜歡用構(gòu)造函數(shù)伶贰,你可以選擇能令你更舒服的那種。
1.5 訪問(wèn)屬性
屬性時(shí)對(duì)象中保存的名字和值的配對(duì)罐栈。點(diǎn)號(hào)時(shí)javascript中訪問(wèn)屬性的最通用的做法(就跟許多面向?qū)ο蟮恼Z(yǔ)言一樣)黍衙,不過(guò)也可以用中括號(hào)訪問(wèn)javascript對(duì)象的屬性。
例如荠诬,下面的代碼使用點(diǎn)號(hào)琅翻。
var array=[];
array.push(12345);
也可以如下例用中括號(hào),方法的名字現(xiàn)在由中括號(hào)中的字符串表示柑贞。
var array=[];
array["push"](12345);
在需要?jiǎng)討B(tài)決定訪問(wèn)那個(gè)屬性的時(shí)候方椎,這個(gè)語(yǔ)法特別游泳。例如下例中的中括號(hào)允許你用變量而不是字符串字面形式來(lái)制定訪問(wèn)的屬性钧嘶。
var array=[];
var method="push";
array[method](12345);
在這段代碼中棠众,變量method的值時(shí)“push”,因此在array上調(diào)用了push()方法有决。這種能力及其有用闸拿,你會(huì)在本書(shū)中隨處看到這種用法。記住一點(diǎn):除了語(yǔ)法不同书幕,在性能或其他方面點(diǎn)號(hào)和中括號(hào)都大致相同新荤,唯一的區(qū)別在於中括號(hào)允許你在屬性名字上使用特殊字符。開(kāi)發(fā)者通常認(rèn)為點(diǎn)號(hào)更加容易讀台汇,所以你更多的看到點(diǎn)號(hào)而不是中括號(hào)苛骨。
1.6 鑒別引用類(lèi)型
函數(shù)是最容易鑒別的引用類(lèi)型,因?yàn)閷?duì)眼熟使用typeof操作符時(shí)苟呐,返回值是“function”掠抬。
function reflect(value){
return value;
}
console.log(typeof reflect);//function
對(duì)其他引用類(lèi)型的鑒別則較為棘手腰奋,因?yàn)閷?duì)於非函數(shù)的引用類(lèi)型屈留,typeof返回“object”康二。在處理很多不同類(lèi)型的時(shí)候幫不上什麼忙,為了更方便的鑒別引用類(lèi)型,可以使用javascript的instanceof操作符。
instanceof 操作符以一個(gè)對(duì)象和一個(gè)構(gòu)造函數(shù)為參數(shù)。如果對(duì)象是構(gòu)造函數(shù)所制定的類(lèi)型的一個(gè)實(shí)例刀诬,instanceof返回ture糠馆;否則返回false,如下例:
var items =[];
var object={};
function reflect(value){
return value;
}
console.log(items instanceof Array); //true
console.log(object instanceof Object);//true
console.log(reflect instanceof Function); //true
本例用instanceof和構(gòu)造函數(shù)測(cè)試了幾個(gè)值皂岔,它們真正的類(lèi)型都正確鑒別出來(lái)(即使該構(gòu)造函數(shù)並沒(méi)有被用於創(chuàng)造該變量)圾笨。
instanceof操作符可鑒別繼承類(lèi)型谍婉。這意味著所有對(duì)象都是object的實(shí)例,因?yàn)樗幸妙?lèi)型都繼承自object。
1.7 鑒別數(shù)組
雖然拷况,instanceof可以鑒別數(shù)組作煌,但是有一個(gè)例外會(huì)影響網(wǎng)頁(yè)開(kāi)發(fā)者:javascript的值可以在同一個(gè)網(wǎng)頁(yè)的不同框架之間傳來(lái)傳去。當(dāng)你試圖鑒別一個(gè)引用值的類(lèi)型的時(shí)候赚瘦,這就有有可能成為一個(gè)問(wèn)題粟誓,因?yàn)槊恳粋€(gè)頁(yè)面擁有它自己的上下文-Object,Array以及其他內(nèi)建類(lèi)型的版本起意。結(jié)果鹰服,當(dāng)你把一個(gè)數(shù)組從一個(gè)框架傳到另一個(gè)框架時(shí),instanceof就無(wú)法識(shí)別它揽咕,因?yàn)槟莻€(gè)數(shù)組時(shí)來(lái)自不同框架的array的實(shí)例悲酷。
為了解決這個(gè)問(wèn)題,ECMAScript5引入了array.isArray()來(lái)明確鑒別一個(gè)值是否為array的實(shí)例亲善,無(wú)論該值來(lái)自哪裏該方法對(duì)來(lái)自任何上下文的數(shù)組都返回true舔涎。如果你的環(huán)境兼容ECMAScript 5,Array逗爹。isArray()是鑒別數(shù)組的最佳辦法。
var items=[];
console.log(Array.isArray(items));//true
大多數(shù)環(huán)境都在瀏覽器和node中指出這個(gè)方法,ie8或更糟的版本不支持該方法
1.8 原始封裝類(lèi)型
javascript中一個(gè)最讓人困惑的部分可能就是原始封裝類(lèi)型掘而。原始封裝類(lèi)型共有三種(String,Number and Boolean) ?這些特殊引用類(lèi)型的存在使得原始類(lèi)型用起來(lái)和對(duì)象一樣方便挟冠。(如果你不得不用獨(dú)特的語(yǔ)法和或切換為基於過(guò)程的編成方式來(lái)獲取一個(gè)字符串,那就太讓人困惑了)袍睡。
當(dāng)獲取字符串知染,數(shù)字或布爾值,原始封裝類(lèi)型將被自動(dòng)創(chuàng)建斑胜。例如控淡,下面代碼第一行,一個(gè)原始字符串的值被賦給name止潘,第二行代碼把name當(dāng)成一個(gè)對(duì)象掺炭,使用點(diǎn)號(hào)調(diào)用了charAt方法
var name ="Nicholas";
var firstChar=name.charAt(0);
console.log(firstChar);
這是在背後發(fā)生的事情如下:
//what the Javascript engine does
var name ="Nicholas";
var temp =new String(name);
var firstChar=temp.CharAt(0);
temp =null;
console.log(firstChar);
由於第二行把字符串當(dāng)成對(duì)象使用,javascript引擎創(chuàng)建了一個(gè)字符串實(shí)體讓charAt(0)可以工作凭戴。字符串對(duì)象的存在僅僅用於該語(yǔ)句並在隨後被銷(xiāo)毀(一個(gè)稱(chēng)為自動(dòng)打包的過(guò)程)涧狮。為了測(cè)試這多一點(diǎn)。試著給字符串添加一個(gè)屬性看看它是不是對(duì)象么夫。
var name="Nicholeas";
name.last="Zakas";
console.log(name.last); ?//undefined
這段代碼試圖給字符串name添加last屬性者冤,代碼運(yùn)行時(shí)沒(méi)有錯(cuò)誤,但是屬性消失了档痪,到底放生了什麼涉枫?你可以在任何時(shí)候給一個(gè)真的對(duì)象添加屬性,屬性會(huì)保留至你手動(dòng)刪除他們腐螟。原始封裝類(lèi)型的屬性會(huì)消失時(shí)因?yàn)樘砑訉傩缘膶?duì)象立刻就被銷(xiāo)毀了愿汰。
下面是在javascript引擎中實(shí)際發(fā)生的事情。
//what the javascript engine does
var name="Nicholas";
var temp = new String(name);
temp.last="Zakas";
temp =null;
var temp = new String(name);
console.log(temp.last);
temp=null;
實(shí)際上是在一個(gè)立刻就被銷(xiāo)毀的臨時(shí)對(duì)象上而不是字符串上添加了新的屬性遭垛,之後當(dāng)你試圖訪問(wèn)該屬性時(shí)尼桶,另一個(gè)不同的臨時(shí)對(duì)象被創(chuàng)建,而新屬性是不存在的锯仪。雖然原始封裝類(lèi)型會(huì)被自動(dòng)創(chuàng)建泵督,在這些值上進(jìn)行instanceof檢查對(duì)應(yīng)類(lèi)型的返回值都是false。
var name ="Nicholas";
var count =0;
var found =false;
console.log(name instanceof String ); //false
console.log(count instanceof ?Number) //false
console.log(found instanceof Boolean) //false
這是因爲(wèi)臨時(shí)對(duì)象僅在值被讀取時(shí)創(chuàng)建庶喜。instanceof操作符並沒(méi)有真的讀取任何東西小腊,也沒(méi)有臨時(shí)對(duì)象的創(chuàng)建,於是它告訴我們這些值並不屬於原始封裝類(lèi)型久窟。你也可以手動(dòng)創(chuàng)建原始封裝類(lèi)型秩冈,但是有某些副作用。
手動(dòng)創(chuàng)建原始封裝類(lèi)型實(shí)際會(huì)創(chuàng)建出一個(gè)object斥扛,這意味著typeof無(wú)法鑑別出來(lái)你實(shí)際保存的數(shù)據(jù)的類(lèi)型入问。
另外,使用String,Number和Boolean對(duì)象和使用原始值有一定區(qū)別芬失。例如楣黍,下列代碼使用了Boolean對(duì)象,對(duì)象的值是false棱烂,但是console.log("Found")亦然會(huì)被執(zhí)行租漂,這是因爲(wèi)inyige對(duì)象在條件判斷語(yǔ)句中總是被認(rèn)爲(wèi)是true,無(wú)論該對(duì)象的值是不是等於false颊糜。
var found=new Boolean(false);
if(found){
console.log("Found");//this excutes
}
手工創(chuàng)建的原始封裝類(lèi)型在其他地方很容易讓人誤解哩治,在大多數(shù)情況下都只會(huì)導(dǎo)致錯(cuò)誤,所以衬鱼,除非有特殊情況业筏,否則你應(yīng)該避免這麼做。
1.9 總結(jié)
javascript中雖然沒(méi)有類(lèi)馁启,但是有類(lèi)型驾孔。每個(gè)變量或數(shù)據(jù)都有一個(gè)對(duì)應(yīng)的原始類(lèi)型或引用類(lèi)型。5種原始類(lèi)型(字符串惯疙,數(shù)字翠勉,布爾,空類(lèi)型和未定義)的值會(huì)被直接保存在變量對(duì)象中霉颠,除了空類(lèi)型对碌,都可以用typefo來(lái)鑑別,空類(lèi)型必須直接跟null進(jìn)行比較才能鑑別蒿偎。
引用類(lèi)型是javascript中最接近類(lèi)的東西朽们,而對(duì)戲則是引用類(lèi)型的實(shí)例∷呶唬可以用new操作符或字面形式創(chuàng)建新對(duì)象骑脱。通常可以用點(diǎn)號(hào)訪問(wèn)屬性和方法苍糠,也可以用中括號(hào)叁丧,函數(shù)在javascript中也是對(duì)象,可以用typeof來(lái)鑑別它們岳瞭。至於其他引用類(lèi)型拥娄,你應(yīng)該用instanceof和一個(gè)構(gòu)造函數(shù)來(lái)鑑別。
爲(wèi)了讓原始類(lèi)型看上去更像引用類(lèi)型瞳筏,javascript提供了3種原始封裝類(lèi)型:String和Number 還有Bolean稚瘾,javascript會(huì)在背後創(chuàng)建這些對(duì)象使你能夠像使用普通對(duì)象那樣使用原始值,但是這些臨時(shí)對(duì)象在使用它們的語(yǔ)句結(jié)束的時(shí)候立刻被銷(xiāo)毀了姚炕,雖然你可以自己創(chuàng)建原始封裝類(lèi)型的實(shí)例摊欠,但是它們太容易讓人誤解了丢烘,所以最好別這麼幹。