JS基礎(chǔ)之?dāng)?shù)據(jù)類型詳解

關(guān)于數(shù)據(jù)類型的一些誤解

網(wǎng)上關(guān)于js數(shù)據(jù)類型的資料都比較混亂烦磁。如 W3school 里的表述:JavaScript 變量能夠保存多種數(shù)據(jù)類型(數(shù)值淡喜、字符串值、數(shù)組齐苛、對象等等)怎披。菜鳥教程也將數(shù)組(Array)胸嘁、函數(shù)(Function)列為與String等并列的數(shù)據(jù)類型。某些介紹JS數(shù)據(jù)類型的技術(shù)博客凉逛,通篇只講了怎么區(qū)分 object性宏、function 和 array。但嚴格來講状飞,function 和 array 并不是一種數(shù)據(jù)類型毫胜。

謹記:在ECMAScript中书斜,數(shù)據(jù)類型只有 7 種,String酵使、Number荐吉、Boolean、Null口渔、Undefined样屠、Symbol(ES6新增)、Object缺脉,其他的都不是痪欲。這7中可以分為基本類型(另一些叫法:簡單類型/原始類型)和引用類型(另一些叫法:復(fù)雜類型)。上面7種類型基本都能用 typeof 操作符來檢測(除了 null 返回 "object" 攻礼、函數(shù)返回 "function")业踢。其中 Object 是引用類型,其他的都是基本類型礁扮。

從技術(shù)角度講陨亡,函數(shù)在 ECMAScript 中是對象,不是一種數(shù)據(jù)類型深员。然而负蠕,函數(shù)也確實有一些特殊的屬性,因此通過 typeof 操作符來區(qū)分函數(shù)和其他對象是有必要的倦畅。從邏輯角度來看遮糖,null值表示一個空對象指針,而這也正是使用 typeof 操作符檢測 null 值時返回 "object" 的原因叠赐。

數(shù)據(jù)類型

Undefined類型

Undefined 類型只有一個值欲账,使用 var 聲明變量,但未對其加以初始化時芭概,這個變量值就是undefined赛不。一般而言,不存在需要顯式把一個變量設(shè)置為 undefined 的情況罢洲。

Null類型

Null 是第二個只有一個值的數(shù)據(jù)類型踢故。null == undefined 返回true。盡管如此惹苗,它倆的用途卻完全不同殿较。如前所述,無論什么時候桩蓉,都不要把一個變量的值顯式地聲明為 undefined淋纲,可是同樣的規(guī)則對null 并不適用。只要意在保存對象的變量還沒有真正保存對象院究,就應(yīng)該明確地讓該變量保存 null 值洽瞬。這樣做不僅可以體現(xiàn) null 作為空對象指針的慣例本涕,也有助于進一步區(qū)分 null 和 undefined。

Boolean類型

該類型只有兩個字面值伙窃,true 和 false菩颖。這兩個值和數(shù)字值不是一回事,因此 true 不一定等于 1对供,false 也不一定等于 0位他。要將一個值轉(zhuǎn)換為其對應(yīng)的 boolean 值氛濒,可以調(diào)用函數(shù) Boolean()产场。可以對任何數(shù)據(jù)類型的值調(diào)用Boolean()函數(shù)舞竿,而且總會返回一個Boolean 值京景。至于返回的這個值是true 還是false,取決于要轉(zhuǎn)換值的數(shù)據(jù)類型及其實際值骗奖。

一般來說确徙,String 類型中任何非空字符串返回 true,空字符串("")返回 false执桌;Number 類型中任何非零數(shù)字值(包括無窮大)返回 true鄙皇, 0 和 NaN 返回 false;Object 類型中任何對象返回 true仰挣, null返回 false伴逸;Undefined 類型返回 false。

Number類型

Number 類型定義了不同的數(shù)值字面量格式膘壶。最基本的數(shù)值字面量格式是十進制整數(shù)错蝴,除了以十進制表示外,整數(shù)還可以通過八進制(以8 為基數(shù))或十六進制(以16 為基數(shù))的字面值來表示颓芭。其中顷锰,八進制字面值的第一位必須是零(0),然后是八進制數(shù)字序列(0~7)亡问。如果字面值中的數(shù)值超出了范圍官紫,那么前導(dǎo)零將被忽略,后面的數(shù)值將被當(dāng)作十進制數(shù)值解析州藕。請看下面的例子:

var intNum = 55; // 整數(shù)
var octalNum1 = 070; // 八進制的56
var octalNum2 = 079; // 無效的八進制數(shù)值——解析為79
var octalNum3 = 08; // 無效的八進制數(shù)值——解析為8

八進制字面量在嚴格模式下是無效的万矾,會導(dǎo)致支持的JavaScript 引擎拋出錯誤。十六進制字面值的前兩位必須是0x慎框,后跟任何十六進制數(shù)字(0~9 及A~F)良狈。其中,字母A~F可以大寫笨枯,也可以小寫薪丁。如下面的例子所示:

var hexNum1 = 0xA; // 十六進制的10
var hexNum2 = 0x1f; // 十六進制的31

在進行算術(shù)計算時遇西,所有以八進制和十六進制表示的數(shù)值最終都將被轉(zhuǎn)換成十進制數(shù)值。

1) 浮點數(shù)值

所謂浮點數(shù)值严嗜,就是該數(shù)值中必須包含一個小數(shù)點粱檀,并且小數(shù)點后面必須至少有一位數(shù)字。由于保存浮點數(shù)值需要的內(nèi)存空間是保存整數(shù)值的兩倍漫玄,因此ECMAScript 會不失時機地將浮點數(shù)值轉(zhuǎn)換為整數(shù)值茄蚯。顯然,如果小數(shù)點后面沒有跟任何數(shù)字睦优,那么這個數(shù)值就可以作為整數(shù)值來保存渗常。同樣地,如果浮點數(shù)值本身表示的就是一個整數(shù)(如1.0)汗盘,那么該值也會被轉(zhuǎn)換為整數(shù)皱碘,如下面的例子所示:

var floatNum1 = 1.; // 小數(shù)點后面沒有數(shù)字——解析為1
var floatNum2 = 10.0; // 整數(shù)——解析為10

在默認情況下,ECMASctipt 會將那些小數(shù)點后面帶有6 個零以上的浮點數(shù)值轉(zhuǎn)換為以e 表示法表示的數(shù)值(例如隐孽,0.0000003 會被轉(zhuǎn)換成3e-7)癌椿。浮點數(shù)值的最高精度是17 位小數(shù),但在進行算術(shù)計算時其精確度遠遠不如整數(shù)菱阵。例如踢俄,0.1 加0.2的結(jié)果不是0.3,而是0.30000000000000004晴及。因此都办,永遠不要如下面例子那樣,測試某個特定的浮點數(shù)值抗俄。

if (a + b == 0.3){   //  不要做這樣的測試脆丁!
    alert("You got 0.3.");
}

關(guān)于浮點數(shù)值計算會產(chǎn)生舍入誤差的問題,有一點需要明確:這是使用基于IEEE754 數(shù)值的浮點計算的通病动雹,ECMAScript 并非獨此一家槽卫;其他使用相同數(shù)值格式的語言也存在這個問題。

2) 數(shù)值范圍

由于內(nèi)存的限制胰蝠,ECMAScript 并不能保存世界上所有的數(shù)值歼培。ECMAScript 能夠表示的最小數(shù)值保存在 Number.MIN_VALUE 中——在大多數(shù)瀏覽器中,這個值是 5e-324茸塞;能夠表示的最大數(shù)值保存在Number.MAX_VALUE 中——在大多數(shù)瀏覽器中躲庄,這個值是1.7976931348623157e+308。如果某次計算的結(jié)果得到了一個超出JavaScript 數(shù)值范圍的值钾虐,那么這個數(shù)值將被自動轉(zhuǎn)換成特殊的Infinity 值噪窘。具體來說,如果這個數(shù)值是負數(shù)效扫,則會被轉(zhuǎn)換成-Infinity(負無窮)倔监,如果這個數(shù)值是正數(shù)直砂,則會被轉(zhuǎn)換成Infinity(正無窮)。

如上所述浩习,如果某次計算返回了正或負的Infinity 值静暂,那么該值將無法繼續(xù)參與下一次的計算,
因為Infinity 不是能夠參與計算的數(shù)值谱秽。要想確定一個數(shù)值是不是有窮的(換句話說洽蛀,是不是位于最小和最大的數(shù)值之間),可以使用isFinite()函數(shù)疟赊。這個函數(shù)在參數(shù)位于最小與最大數(shù)值之間時會返回true郊供,如下面的例子所示:

var result = Number.MAX_VALUE + Number.MAX_VALUE;
alert(isFinite(result));  // false

盡管在計算中很少出現(xiàn)某些值超出表示范圍的情況,但在執(zhí)行極小或極大數(shù)值的計算時听绳,檢測監(jiān)控這些值是可能的颂碘,也是必需的异赫。訪問 Number.NEGATIVE_INFINITY 和 Number.POSITIVE_INFINITY也可以得到負和正 Infinity 的值椅挣。可以想見塔拳,這兩個屬性中分別保存著-Infinity 和 Infinity鼠证。

3) NaN

NaN,即非數(shù)值(Not a Number)是一個特殊的數(shù)值靠抑,這個數(shù)值用于表示一個本來要返回數(shù)值的操作數(shù)未返回數(shù)值的情況(這樣就不會拋出錯誤了)量九。例如,在其他編程語言中颂碧,任何數(shù)值除以 0 都會導(dǎo)致錯誤荠列,從而停止代碼執(zhí)行。但在ECMAScript 中载城,任何數(shù)值除以0 會返回NaN肌似,因此不會影響其他代碼的執(zhí)行。NaN 本身有兩個非同尋常的特點诉瓦。首先川队,任何涉及NaN 的操作(例如NaN/10)都會返回NaN,這個特點在多步計算中有可能導(dǎo)致問題睬澡。其次固额,NaN 與任何值都不相等,包括NaN 身煞聪。

針對NaN 的這兩個特點斗躏,ECMAScript 定義了isNaN()函數(shù)。這個函數(shù)接受一個參數(shù)昔脯,該參數(shù)可以是任何類型啄糙,而函數(shù)會幫我們確定這個參數(shù)是否“不是數(shù)值”馋艺。而任何不能被轉(zhuǎn)換為數(shù)值的值都會導(dǎo)致這個函數(shù)返回 true。例子:


alert(isNaN(NaN)); //true
alert(isNaN(10)); //false(10 是一個數(shù)值)
alert(isNaN("10")); //false(可以被轉(zhuǎn)換成數(shù)值10)
alert(isNaN("blue")); //true(不能轉(zhuǎn)換成數(shù)值)
alert(isNaN(true)); //false(可以被轉(zhuǎn)換成數(shù)值1)

盡管有點兒不可思議迈套,但isNaN()確實也適用于對象捐祠。在基于對象調(diào)用isNaN()函數(shù)時,會首先調(diào)用對象的valueOf()方法桑李,然后確定該方法返回的值是否可以轉(zhuǎn)換為數(shù)值踱蛀。如果不能,則基于這個返回值再調(diào)用toString()方法贵白,再測試返回值率拒。而這個過程也是ECMAScript 中內(nèi)置函數(shù)和操作符的一般執(zhí)行流程

4) 數(shù)值轉(zhuǎn)換

有3 個函數(shù)可以把非數(shù)值轉(zhuǎn)換為數(shù)值:Number()、parseInt()和parseFloat()禁荒。第一個函數(shù)猬膨,即轉(zhuǎn)型函數(shù)Number()可以用于任何數(shù)據(jù)類型,而另兩個函數(shù)則專門用于把字符串轉(zhuǎn)換成數(shù)值呛伴。這3 個函數(shù)對于同樣的輸入會有返回不同的結(jié)果勃痴。Number()函數(shù)的轉(zhuǎn)換規(guī)則如下。
? 如果是Boolean 值热康,true 和false 將分別被轉(zhuǎn)換為1 和0沛申。
? 如果是數(shù)字值,只是簡單的傳入和返回姐军。
? 如果是null 值铁材,返回0。
? 如果是undefined奕锌,返回NaN著觉。
? 如果是字符串,遵循下列規(guī)則:

  • 如果字符串中只包含數(shù)字(包括前面帶正號或負號的情況)惊暴,則將其轉(zhuǎn)換為十進制數(shù)值饼丘,即"1"會>變成1,"123"會變成123缴守,而"011"會變成11(注意:前導(dǎo)的零被忽略了)葬毫;
  • 如果字符串中包含有效的浮點格式,如"1.1"屡穗,則將其轉(zhuǎn)換為對應(yīng)的浮點數(shù)值(同樣贴捡,也會忽略前導(dǎo)零);
  • 如果字符串中包含有效的十六進制格式村砂,例如"0xf"烂斋,則將其轉(zhuǎn)換為相同大小的十進制整數(shù)值;
  • 如果字符串是空的(不包含任何字符),則將其轉(zhuǎn)換為0汛骂;
  • 如果字符串中包含除上述格式之外的字符罕模,則將其轉(zhuǎn)換為NaN。

? 如果是對象帘瞭,則調(diào)用對象的valueOf()方法淑掌,然后依照前面的規(guī)則轉(zhuǎn)換返回的值。如果轉(zhuǎn)換的結(jié)果是NaN蝶念,則調(diào)用對象的toString()方法抛腕,然后再次依照前面的規(guī)則轉(zhuǎn)換返回的字符串值。

例子:

var num1 = Number("Hello world!"); //NaN
var num2 = Number(""); //0
var num3 = Number("000011"); //11
var num4 = Number(true); //1

由于Number()函數(shù)在轉(zhuǎn)換字符串時比較復(fù)雜而且不夠合理媒殉,因此在處理整數(shù)的時候更常用的是parseInt() 函數(shù)担敌。parseInt()函數(shù)在轉(zhuǎn)換字符串時,更多的是看其是否符合數(shù)值模式廷蓉。它會忽略字符串前面的空格全封,直至找到第一個非空格字符。如果第一個字符不是數(shù)字字符或者負號桃犬,parseInt() 就會返回 NaN刹悴;也就是說,用 parseInt() 轉(zhuǎn)換空字符串會返回 NaN(Number() 對空字符返回0)疫萤。如果第一個字符是數(shù)字字符颂跨,parseInt() 會繼續(xù)解析第二個字符敢伸,直到解析完所有后續(xù)字符或者遇到了一個非數(shù)字字符扯饶。例如,"1234blue" 會被轉(zhuǎn)換為1234池颈,因為"blue"會被完全忽略尾序。類似地,"22.5"會被轉(zhuǎn)換為22躯砰,因為小數(shù)點并不是有效的數(shù)字字符每币。

如果字符串中的第一個字符是數(shù)字字符,parseInt() 也能夠識別出各種整數(shù)格式(即前面討論的十進制琢歇、八進制和十六進制數(shù))兰怠。也就是說,如果字符串以"0x"開頭且后跟數(shù)字字符李茫,就會將其當(dāng)作一個十六進制整數(shù)揭保;如果字符串以"0"開頭且后跟數(shù)字字符,則會將其當(dāng)作一個八進制數(shù)來解析魄宏。例子:

var num1 = parseInt("1234blue"); // 1234
var num2 = parseInt(""); // NaN
var num3 = parseInt("0xA"); // 10(十六進制數(shù))
var num4 = parseInt(22.5); // 22
var num5 = parseInt("070"); // 56(八進制數(shù))
var num6 = parseInt("70"); // 70(十進制數(shù))
var num7 = parseInt("0xf"); // 15(十六進制數(shù))

在使用parseInt()解析像八進制字面量的字符串時秸侣,ECMAScript 3 和5 存在分歧。例如:

var num = parseInt("070"); // ECMAScript 3 認為是56(八進制),ECMAScript 5 認為是70(十進制)

在ECMAScript 3 JavaScript 引擎中味榛,"070"被當(dāng)成八進制字面量椭坚,因此轉(zhuǎn)換后的值是十進制的56。而在ECMAScript 5 JavaScript 引擎中搏色,parseInt()已經(jīng)不具有解析八進制值的能力善茎,因此前導(dǎo)的零會被認為無效,從而將這個值當(dāng)成"70"频轿,結(jié)果就得到十進制的70巾表。在ECMAScript 5 中,即使是在非嚴格模式下也會如此略吨。為了消除在使用parseInt()函數(shù)時可能導(dǎo)致的上述困惑集币,可以為這個函數(shù)提供第二個參數(shù):轉(zhuǎn)換時使用的基數(shù)(即多少進制)。如果知道要解析的值是十六進制格式的字符串翠忠,那么指定基數(shù)16 作為第二個參數(shù)鞠苟,可以保證得到正確的結(jié)果,例如:

var num = parseInt("0xAF", 16); //175

實際上秽之,如果指定了16 作為第二個參數(shù)当娱,字符串可以不帶前面的"0x",如下所示:

var num1 = parseInt("AF", 16); //175
var num2 = parseInt("AF"); //NaN

這個例子中的第一個轉(zhuǎn)換成功了考榨,而第二個則失敗了跨细。差別在于第一個轉(zhuǎn)換傳入了基數(shù),明確告訴parseInt() 要解析一個十六進制格式的字符串河质;而第二個轉(zhuǎn)換發(fā)現(xiàn)第一個字符不是數(shù)字字符冀惭,因此就自動終止了。指定基數(shù)會影響到轉(zhuǎn)換的輸出結(jié)果掀鹅。例如:

var num1 = parseInt("10", 2); //2 (按二進制解析)
var num2 = parseInt("10", 8); //8 (按八進制解析)
var num3 = parseInt("10", 10); //10 (按十進制解析)
var num4 = parseInt("10", 16); //16 (按十六進制解析)

不指定基數(shù)意味著讓parseInt()決定如何解析輸入的字符串散休,因此為了避免錯誤的解析,我們建議無論在什么情況下都明確指定基數(shù)乐尊。多數(shù)情況下戚丸,我們要解析的都是十進制數(shù)值,因此始終將10 作為第二個參數(shù)是非常必要的扔嵌。

與parseInt()函數(shù)類似限府,parseFloat()也是從第一個字符(位置0)開始解析每個字符。而且也是一直解析到字符串末尾痢缎,或者解析到遇見一個無效的浮點數(shù)字字符為止胁勺。也就是說,字符串中的第一個小數(shù)點是有效的牺弄,而第二個小數(shù)點就是無效的了姻几,因此它后面的字符串將被忽略宜狐。舉例來說,"22.34.5"將會被轉(zhuǎn)換為22.34蛇捌。

除了第一個小數(shù)點有效之外抚恒,parseFloat() 與 parseInt() 的第二個區(qū)別在于它始終都會忽略前導(dǎo)的零。parseFloat() 可以識別前面討論過的所有浮點數(shù)值格式络拌,也包括十進制整數(shù)格式俭驮。但十六進制格式的字符串則始終會被轉(zhuǎn)換成0。由于parseFloat()只解析十進制值春贸,因此它沒有用第二個參數(shù)指定基數(shù)的用法混萝。最后還要注意一點:如果字符串包含的是一個可解析為整數(shù)的數(shù)(沒有小數(shù)點,或者小數(shù)點后都是零)萍恕,parseFloat() 會返回整數(shù)逸嘀。以下是使用 parseFloat() 轉(zhuǎn)換數(shù)值的幾個典型示例。

var num1 = parseFloat("1234blue"); //1234 (整數(shù))
var num2 = parseFloat("0xA"); //0
var num3 = parseFloat("22.5"); //22.5
var num4 = parseFloat("22.34.5"); //22.34
var num5 = parseFloat("0908.5"); //908.5
var num6 = parseFloat("3.125e7"); //31250000

String 類型

1) 字符串的特點

ECMAScript 中的字符串是不可變的允粤,也就是說崭倘,字符串一旦創(chuàng)建,它們的值就不能改變类垫。要改變某個變量保存的字符串司光,首先要銷毀原來的字符串,然后再用另一個包含新值的字符串填充該變量悉患,例如:

var lang = "Java";
lang = lang + "Script";

以上示例中的變量lang 開始時包含字符串"Java"残家。而第二行代碼把lang 的值重新定義為"Java"
與"Script"的組合,即"JavaScript"售躁。實現(xiàn)這個操作的過程如下:首先創(chuàng)建一個能容納10 個字符的新字符串坞淮,然后在這個字符串中填充"Java"和"Script",最后一步是銷毀原來的字符串"Java"和字符串"Script"迂求,因為這兩個字符串已經(jīng)沒用了碾盐。這個過程是在后臺發(fā)生的,而這也是在某些舊版本的瀏覽器(例如版本低于1.0 的Firefox揩局、IE6 等)中拼接字符串時速度很慢的原因所在。但這些瀏覽器后來的版本已經(jīng)解決了這個低效率問題掀虎。

2) 字符串轉(zhuǎn)換

要把一個值轉(zhuǎn)換為一個字符串有兩種方式凌盯。第一種是使用幾乎每個值都有的toString()方法。這個方法唯一要做的就是返回相應(yīng)值的字符串表現(xiàn)烹玉。例子:

var age = 11;
var ageAsString = age.toString(); // 字符串"11"
var found = true;
var foundAsString = found.toString(); // 字符串"true"

數(shù)值驰怎、布爾值、對象和字符串值(沒錯二打,每個字符串也都有一個toString()方法县忌,該方法返回字符串的一個副本)都有toString()方法。但null 和undefined 值沒有這個方法。

多數(shù)情況下症杏,調(diào)用toString()方法不必傳遞參數(shù)装获。但是,在調(diào)用數(shù)值的toString()方法時厉颤,可以傳遞一個參數(shù):輸出數(shù)值的基數(shù)穴豫。默認情況下,toString()方法以十進制格式返回數(shù)值的字符串表示逼友。而通過傳遞基數(shù)精肃,toString()可以輸出以二進制、八進制帜乞、十六進制司抱,乃至其他任意有效進制格式表示的字符串值。例子:

var num = 10;
alert(num.toString()); // "10"
alert(num.toString(2)); // "1010"
alert(num.toString(8)); // "12"
alert(num.toString(10)); // "10"
alert(num.toString(16)); // "a"

通過這個例子可以看出黎烈,通過指定基數(shù)状植,toString() 方法會改變輸出的值。而數(shù)值10 根據(jù)基數(shù)的不同怨喘,可以在輸出時被轉(zhuǎn)換為不同的數(shù)值格式津畸。注意,默認的(沒有參數(shù)的)輸出值與指定基數(shù)10 時的輸出值相同必怜。

在不知道要轉(zhuǎn)換的值是不是null 或undefined 的情況下肉拓,還可以使用轉(zhuǎn)型函數(shù)String(),這個函數(shù)能夠?qū)⑷魏晤愋偷闹缔D(zhuǎn)換為字符串梳庆。String()函數(shù)遵循下列轉(zhuǎn)換規(guī)則:

? 如果值有 toString() 方法暖途,則調(diào)用該方法(沒有參數(shù))并返回相應(yīng)的結(jié)果;
? 如果值是 null膏执,則返回 "null"驻售;
? 如果值是 undefined,則返回 "undefined" 更米。

例子:

var value1 = 10;
var value2 = true;
var value3 = null;
var value4;
alert(String(value1)); // "10"
alert(String(value2)); // "true"
alert(String(value3)); // "null"
alert(String(value4)); // "undefined"

這里先后轉(zhuǎn)換了4 個值:數(shù)值欺栗、布爾值、null 和 undefined征峦。數(shù)值和布爾值的轉(zhuǎn)換結(jié)果與調(diào)用toString() 方法得到的結(jié)果相同迟几。因為 null 和 undefined 沒有 toString() 方法,所以 String() 函數(shù)就返回了這兩個值的字面量栏笆。要把某個值轉(zhuǎn)換為字符串类腮,可以使用加號操作符把它與一個字符串("")加在一起。

Object類型

ECMAScript 中的對象其實就是一組數(shù)據(jù)和功能的集合蛉加。對象可以通過執(zhí)行 new 操作符后跟要創(chuàng)建的對象類型的名稱來創(chuàng)建蚜枢。而創(chuàng)建Object 類型的實例并為其添加屬性和(或)方法缸逃,就可以創(chuàng)建自定義對象。

僅僅創(chuàng)建Object 的實例并沒有什么用處厂抽,但關(guān)鍵是要理解一個重要的思想:即在ECMAScript 中需频,Object 類型是所有它的實例的基礎(chǔ)。換句話說修肠,Object 類型所具有的任何屬性和方法也同樣存在于更具體的對象中贺辰。Object 的每個實例都具有下列屬性和方法。

? constructor:保存著用于創(chuàng)建當(dāng)前對象的函數(shù)嵌施。對于前面的例子而言饲化,構(gòu)造函數(shù)(constructor)就是Object()。
? hasOwnProperty(propertyName):用于檢查給定的屬性在當(dāng)前對象實例中(而不是在實例的原型中)是否存在吗伤。其中吃靠,作為參數(shù)的屬性名(propertyName)必須以字符串形式指定(例如:o.hasOwnProperty("name"))。
? isPrototypeOf(object):用于檢查傳入的對象是否是傳入對象的原型(第5 章將討論原型)足淆。
? propertyIsEnumerable(propertyName):用于檢查給定的屬性是否能夠使用for-in 語句來枚舉巢块。與hasOwnProperty() 方法一樣,作為參數(shù)的屬性名必須以字符串形式指定巧号。
? toLocaleString():返回對象的字符串表示族奢,該字符串與執(zhí)行環(huán)境的地區(qū)對應(yīng)。
? toString():返回對象的字符串表示丹鸿。
? valueOf():返回對象的字符串越走、數(shù)值或布爾值表示。通常與 toString() 方法的返回值相同靠欢。

由于在ECMAScript 中Object 是所有對象的基礎(chǔ)廊敌,因此所有對象都具有這些基本的屬性和方法。但ECMAScript 中對象的行為不一定適用于JavaScript 中的其他對象门怪。瀏覽器環(huán)境中的對象骡澈,比如BOM 和DOM 中的對象,都屬于宿主對象掷空,因為它們是由宿主實現(xiàn)提供和定義的肋殴。ECMA-262 不負責(zé)定義宿主對象,因此宿主對象可能會也可能不會繼承Object拣帽。

關(guān)于Object類型(引用類型)疼电,會在另一篇做單獨整理和解釋。

Symbol類型

ES5 的對象屬性名都是字符串减拭,這容易造成屬性名的沖突。比如区丑,你使用了一個他人提供的對象拧粪,但又想為這個對象添加新的方法(mixin 模式)修陡,新方法的名字就有可能與現(xiàn)有方法產(chǎn)生沖突。如果有一種機制可霎,保證每個屬性的名字都是獨一無二的就好了魄鸦,這樣就從根本上防止屬性名的沖突。這就是 ES6 引入Symbol的原因癣朗。

ES6 引入了一種新的原始數(shù)據(jù)類型Symbol拾因,表示獨一無二的值。它是 JavaScript 語言的第七種數(shù)據(jù)類型旷余,前六種是:undefined绢记、null、布爾值(Boolean)正卧、字符串(String)蠢熄、數(shù)值(Number)、對象(Object)炉旷。

Symbol 值通過Symbol函數(shù)生成签孔。這就是說,對象的屬性名現(xiàn)在可以有兩種類型窘行,一種是原來就有的字符串饥追,另一種就是新增的 Symbol 類型。凡是屬性名屬于 Symbol 類型罐盔,就都是獨一無二的但绕,可以保證不會與其他屬性名產(chǎn)生沖突。

let s = Symbol();
typeof s // "symbol"

上面代碼中翘骂,變量s就是一個獨一無二的值壁熄。typeof運算符的結(jié)果,表明變量s是 Symbol 數(shù)據(jù)類型碳竟,而不是字符串之類的其他類型草丧。

注意,Symbol函數(shù)前不能使用new命令莹桅,否則會報錯昌执。這是因為生成的 Symbol 是一個原始類型的值,不是對象诈泼。也就是說懂拾,由于 Symbol 值不是對象,所以不能添加屬性铐达♂常基本上,它是一種類似于字符串的數(shù)據(jù)類型瓮孙。

Symbol函數(shù)可以接受一個字符串作為參數(shù)唐断,表示對 Symbol 實例的描述选脊,主要是為了在控制臺顯示,或者轉(zhuǎn)為字符串時脸甘,比較容易區(qū)分恳啥。


let s1 = Symbol('foo');
let s2 = Symbol('bar');

s1 // Symbol(foo)
s2 // Symbol(bar)

s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"

上面代碼中,s1和s2是兩個 Symbol 值丹诀。如果不加參數(shù)钝的,它們在控制臺的輸出都是Symbol(),不利于區(qū)分铆遭。有了參數(shù)以后硝桩,就等于為它們加上了描述,輸出的時候就能夠分清疚脐,到底是哪一個值亿柑。

如果 Symbol 的參數(shù)是一個對象,就會調(diào)用該對象的toString方法棍弄,將其轉(zhuǎn)為字符串望薄,然后才生成一個 Symbol 值。

const obj = {
  toString() {
    return 'abc';
  }
};
const sym = Symbol(obj);
sym // Symbol(abc)

注意呼畸,Symbol函數(shù)的參數(shù)只是表示對當(dāng)前 Symbol 值的描述痕支,因此相同參數(shù)的Symbol函數(shù)的返回值是不相等的。

// 沒有參數(shù)的情況
let s1 = Symbol();
let s2 = Symbol();

s1 === s2 // false

// 有參數(shù)的情況
let s1 = Symbol('foo');
let s2 = Symbol('foo');

s1 === s2 // false

上面代碼中蛮原,s1和s2都是Symbol函數(shù)的返回值卧须,而且參數(shù)相同,但是它們是不相等的儒陨。

Symbol 值不能與其他類型的值進行運算花嘶,會報錯。

let sym = Symbol('My symbol');
"your symbol is " + sym // TypeError: can't convert symbol to string
`your symbol is ${sym}`  // TypeError: can't convert symbol to string

但是蹦漠,Symbol 值可以顯式轉(zhuǎn)為字符串椭员。

let sym = Symbol('My symbol');
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'

另外,Symbol 值也可以轉(zhuǎn)為布爾值笛园,但是不能轉(zhuǎn)為數(shù)值隘击。

let sym = Symbol();
Boolean(sym) // true
!sym  // false
if (sym) {
  // ...
}
Number(sym) // TypeError
sym + 2 // TypeError

更多 symbol 的特性和用法,可參考阮一峰老師的ECMAScript 6 入門中關(guān)于 symbol 的介紹http://es6.ruanyifeng.com/#docs/symbol

該篇筆記主要是復(fù)習(xí)和鞏固基礎(chǔ)內(nèi)容研铆,溫故知新埋同。其中大部分內(nèi)容摘抄自《JavaScript高級程序設(shè)計》第三版。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末棵红,一起剝皮案震驚了整個濱河市凶赁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖哟冬,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件楼熄,死亡現(xiàn)場離奇詭異忆绰,居然都是意外死亡浩峡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門错敢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翰灾,“玉大人,你說我怎么就攤上這事稚茅≈交矗” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵亚享,是天一觀的道長咽块。 經(jīng)常有香客問我,道長欺税,這世上最難降的妖魔是什么侈沪? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任爬骤,我火速辦了婚禮蔬充,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘欣喧。我一直安慰自己歼秽,他們只是感情好应役,可當(dāng)我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著燥筷,像睡著了一般箩祥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上肆氓,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天袍祖,我揣著相機與錄音,去河邊找鬼做院。 笑死盲泛,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的键耕。 我是一名探鬼主播寺滚,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼屈雄!你這毒婦竟也來了村视?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤酒奶,失蹤者是張志新(化名)和其女友劉穎蚁孔,沒想到半個月后奶赔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡杠氢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年站刑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鼻百。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡绞旅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出温艇,到底是詐尸還是另有隱情因悲,我是刑警寧澤,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布勺爱,位于F島的核電站晃琳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏琐鲁。R本人自食惡果不足惜卫旱,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绣否。 院中可真熱鬧誊涯,春花似錦、人聲如沸蒜撮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽段磨。三九已至取逾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間苹支,已是汗流浹背砾隅。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留债蜜,地道東北人晴埂。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像寻定,于是被迫代替她去往敵國和親儒洛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,494評論 2 348

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

  • ??引用類型的值(對象)是引用類型的一個實例。 ??在 ECMAscript 中,引用類型是一種數(shù)據(jù)結(jié)構(gòu)恼蓬,用于將數(shù)...
    霜天曉閱讀 1,042評論 0 1
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,216評論 0 4
  • 第3章 基本概念 3.1 語法 3.2 關(guān)鍵字和保留字 3.3 變量 3.4 數(shù)據(jù)類型 5種簡單數(shù)據(jù)類型:Unde...
    RickCole閱讀 5,104評論 0 21
  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,370評論 0 5
  • [TOC] 參考阮一峰的ECMAScript 6 入門參考深入淺出ES6 let和const let和const都...
    郭子web閱讀 1,773評論 0 1