第一章 原始類(lèi)型和引用類(lèi)型

大多數(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í)例摊欠,但是它們太容易讓人誤解了丢烘,所以最好別這麼幹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凄硼,一起剝皮案震驚了整個(gè)濱河市铅协,隨后出現(xiàn)的幾起案子坏平,更是在濱河造成了極大的恐慌盛卡,老刑警劉巖摩钙,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異说墨,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)苍柏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)尼斧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人试吁,你說(shuō)我怎么就攤上這事棺棵。” “怎么了熄捍?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵烛恤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我余耽,道長(zhǎng)缚柏,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任碟贾,我火速辦了婚禮币喧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘袱耽。我一直安慰自己杀餐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布朱巨。 她就那樣靜靜地躺著史翘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蔬崩。 梳的紋絲不亂的頭發(fā)上恶座,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音沥阳,去河邊找鬼跨琳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛桐罕,可吹牛的內(nèi)容都是我干的脉让。 我是一名探鬼主播桂敛,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼溅潜!你這毒婦竟也來(lái)了术唬?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤滚澜,失蹤者是張志新(化名)和其女友劉穎粗仓,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體设捐,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡借浊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了萝招。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚂斤。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖槐沼,靈堂內(nèi)的尸體忽然破棺而出曙蒸,到底是詐尸還是另有隱情,我是刑警寧澤岗钩,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布纽窟,位于F島的核電站,受9級(jí)特大地震影響凹嘲,放射性物質(zhì)發(fā)生泄漏师倔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一周蹭、第九天 我趴在偏房一處隱蔽的房頂上張望趋艘。 院中可真熱鬧,春花似錦凶朗、人聲如沸瓷胧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)搓萧。三九已至,卻和暖如春宛畦,著一層夾襖步出監(jiān)牢的瞬間瘸洛,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工次和, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留反肋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓踏施,卻偏偏與公主長(zhǎng)得像石蔗,于是被迫代替她去往敵國(guó)和親罕邀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 也許你還沒(méi)有理解構(gòu)造函數(shù)和原型對(duì)象的時(shí)候已經(jīng)在javascript的路上走了很久养距,但直到你很好的掌握它們之前你不會(huì)...
    WanLum閱讀 411評(píng)論 0 1
  • 盡管javascript里有大量?jī)?nèi)建引用對(duì)象诉探,很可能你還說(shuō)會(huì)頻繁創(chuàng)建自己的對(duì)象。當(dāng)你在這么做的時(shí)候棍厌,記得javas...
    WanLum閱讀 531評(píng)論 1 3
  • 學(xué)習(xí)如何創(chuàng)建對(duì)象時(shí)理解面向?qū)ο蟮牡谝徊缴隹琛5诙繒r(shí)理解繼承。在傳統(tǒng)面向?qū)ο蟮恼Z(yǔ)言中定铜,類(lèi)從其他類(lèi)繼承屬性阳液。然而在jav...
    WanLum閱讀 264評(píng)論 0 0
  • javascript有很多創(chuàng)建對(duì)象的模式,完成工作的方式也不只一種揣炕。你可以隨時(shí)定義自己的類(lèi)型或自己的泛用對(duì)象《颍可以...
    WanLum閱讀 265評(píng)論 0 0
  • 由于今天徐老師沒(méi)來(lái)畸陡,上了兩節(jié)英語(yǔ)課,同學(xué)早就疲憊不安虽填。在下一節(jié)的音樂(lè)課中丁恭,大家懶洋洋的一聲“老師好”。便“...
    徐一軒_7bec閱讀 333評(píng)論 0 0