JavaScript 類型

類型

基本類型:Undefined汪榔、Null眉厨、Boolean宴合、String甫菠、Number灵寺、Symbol

引用類型:Object

1. 基本類型和引用類型的區(qū)別

image

上面這張圖片很好的解釋了值傳遞和引用傳遞的區(qū)別脐区。

1.1 不可變性

基本類型弥搞,在 ECMAScript 標準中论巍,它們被定義為 primitive values ,即原始值地沮,代表值本身是不可被改變的。

基本類型的值被直接存儲在棧中羡亩,在變量定義時摩疑,棧就為其分配好了內(nèi)存空間。由于棧中的內(nèi)存空間的大小是固定的畏铆,那么注定了存儲在棧中的變量就是不可變的雷袋。

以字符串為例,我們在調(diào)用操作字符串的方法時,沒有任何方法是可以直接改變字符串的楷怒。對其修改也只是修改變量指向的值蛋勺,而值的本身是不課改變的。

let str = 'str'
str += '1'
console.log(str);  // str1

在上面的代碼 str 是變量名鸠删,'str' 則是一個 String 類型的值抱完,通過 += 這個操作符會將一個新的 String 類型的值 'str1' 賦值給 str 這個變量。值本身是沒有改變的刃泡。

引用類型的值實際存儲在堆內(nèi)存中巧娱,它在棧中只存儲了一個固定長度的地址,這個地址指向堆內(nèi)存中的值烘贴。因此引用類型的值是可以修改的禁添。

1.2 復制

基本類型在復制的時候,會在棧中開辟一個新的內(nèi)存空間來存儲復制出來的值桨踪。這樣以來二者指向的內(nèi)存空間完全不同老翘,這兩個變量的操作就互不影響。

當我們復制引用類型的變量時锻离,實際上復制的是棧中存儲的地址酪捡,因此復制出來的變量實際上和之前的變量指向堆中同一個對象。這樣以來操作會相互影響纳账。

1.3 比較

對于原始類型逛薇,比較時會直接比較它們的值,如果值相等疏虫,即返回 true永罚。

對于引用類型,比較時會比較它們的引用地址卧秘,即使兩個變量在堆中存儲的對象具有的屬性值都是相等的呢袱,但是它們被存儲在了不同的存儲空間,因此比較值為 false翅敌。

1.4 值傳遞和引用傳遞

所有的函數(shù)的參數(shù)都是按值傳遞的羞福。

當函數(shù)參數(shù)是值類型的時候,修改函數(shù)參數(shù)的值是不能修改外部值蚯涮。

當函數(shù)參數(shù)是引用類型時治专,我們同樣將參數(shù)復制了一個副本到局部變量,只不過復制的這個副本是指向堆內(nèi)存中的地址而已遭顶,我們在函數(shù)內(nèi)部對對象的屬性進行操作张峰,實際上和外部變量指向堆內(nèi)存中的值相同,但是這并不代表著引用傳遞棒旗,依然是值傳遞喘批。

2. Undefined

2.1 語義

表示一個變量最原始的狀態(tài),代表未定義的值,而非人為操作的結(jié)果

2.2 本質(zhì)

undefined 是全局對象的一個屬性饶深。也就是說餐曹,它是全局作用域的一個變量,并非一個關(guān)鍵字敌厘。

2.3 獲取 undefined

  • 變量被聲明了台猴,但沒有賦值時,就等于 undefined额湘。
  • 調(diào)用函數(shù)時卿吐,應(yīng)該提供的參數(shù)沒有提供,該參數(shù)等于 undefined锋华。
  • 對象沒有賦值的屬性嗡官,該屬性的值為 undefined。
  • 函數(shù)沒有返回值時(沒有寫 return 或者 return 后面沒有東西)毯焕,默認返回 undefined衍腥。

2.4 void 0 代替 undefined

void 操作符 對任何表達式求值都返回 undefined ,這和函數(shù)執(zhí)行操作后沒有返回值的作用是一樣的纳猫,JavaScript 中的函數(shù)都有返回值婆咸,當沒有 return 操作時,就默認返回一個原始的狀態(tài)值芜辕,這個值就是 undefined尚骄,表明函數(shù)的返回值未被定義。

undefined 是一個變量而不是關(guān)鍵字侵续,為了避免被篡改一般使用 void 0 來獲取 undefined 值倔丈。

3. Null

3.1 語義

表示一個對象被人為的重置為空對象,而非一個變量最原始的狀態(tài)状蜗。它只有一個值需五,即 null。

3.2 本質(zhì)

null 在內(nèi)存里的表示棧中的變量沒有指向堆中的內(nèi)存對象轧坎。當一個對象被賦值了 null 以后宏邮,原來的對象在內(nèi)存中就處于游離狀態(tài),GC 會擇機回收該對象并釋放內(nèi)存缸血。因此蜜氨,如果需要釋放某個對象,就將變量設(shè)置為 null属百,即表示該對象已經(jīng)被清空记劝,目前無效狀態(tài)。

3.3 typeof null == 'object'

typeof 會將 null 誤判為 Object 類型族扰。

這是因為數(shù)據(jù)類型在底層都是以二進制形式表示的,二進制的前三位為 0 會被 typeof 判定為對象類型。

  • 000 - 對象渔呵,數(shù)據(jù)是對象的應(yīng)用
  • 1 - 整型怒竿,數(shù)據(jù)是31位帶符號整數(shù)
  • 010 - 雙精度類型,數(shù)據(jù)是雙精度數(shù)字
  • 100 - 字符串扩氢,數(shù)據(jù)是字符串
  • 110 - 布爾類型耕驰,數(shù)據(jù)是布爾值

null 值的二進制表示全是 0 ,自然前三位當然也是 000录豺,因此朦肘,typeof 會誤以為是對象類型。

3.4 null 和 undefined 的區(qū)別

null 表示無值,即該處不應(yīng)該有值双饥,也沒有指向任何對象或者任何值媒抠,而 undefined 表示缺少值,表示應(yīng)該有值,但是還沒有定義咏花,所以先指向全局變量 window.undefined 或者 undefined 來代替那個還沒有定義的值趴生。

使用 == 只判斷值的時候,null 和 undefined 是一樣的昏翰,但是使用 === 的時候苍匆,需要做類型判斷,null 的類型為 Null, undefined 的類型為 Undefined

4. Boolean

4.1 語義

表示邏輯上的真和假棚菊,它有兩個值 true 和 false

4.2 轉(zhuǎn)化

在 JavaScript 中浸踩,所有類型的值都可以轉(zhuǎn)化為與 Boolean 等價的值。轉(zhuǎn)化規(guī)則如下:

  1. 所有對象都被當作 true
  2. 空字符串被當作 false
  3. null 和 undefined 被當作 false
  4. 數(shù)字 0 和 NaN 被當作 false
  5. 出去 2统求,3检碗,4 之外的值類型都被當做 true

只推薦使用 Boolean() 轉(zhuǎn)換函數(shù)。

4.3 返回 Boolean 的操作符

4.3.1 關(guān)系操作符:>球订,>=后裸,<<=

當關(guān)系操作符的操作數(shù)使用了非數(shù)值時冒滩,要進行數(shù)據(jù)轉(zhuǎn)換或完成某些奇怪的操作微驶。

  • 如果兩個操作數(shù)都是數(shù)值,則執(zhí)行數(shù)值比較开睡。
  • 如果兩個操作數(shù)都是字符串因苹,則逐個比較兩者對應(yīng)的字符編碼(charCode),直到分出大小為止 篇恒。
  • 如果操作數(shù)是其他基本類型扶檐,則調(diào)用 Number() 將其轉(zhuǎn)化為數(shù)值,然后進行比較胁艰。
  • NaN 與任何值比較款筑,均返回 false 智蝠。
  • 如果操作數(shù)是對象,則調(diào)用對象的 valueOf 方法(如果沒有 valueOf 奈梳,就調(diào)用 toString 方法)杈湾,最后用得到的結(jié)果,根據(jù)前面的規(guī)則執(zhí)行比較攘须。

4.3.2 相等操作符: ==漆撞,!====于宙,!==

如果兩個操作數(shù)類型相同則 ==!====!== 是等價的浮驳。

== 和 != 操作符都會先轉(zhuǎn)換操作數(shù),然后再比較它們的相等性捞魁。

  • 如果有一個操作數(shù)是布爾值至会,則在比較相等性之前,先調(diào)用 Number() 將其轉(zhuǎn)換為數(shù)值署驻;
  • 如果一個操作數(shù)是字符串奋献,另一個操作數(shù)是數(shù)值,在比較相等性之前旺上,先調(diào)用 Number() 將字符串轉(zhuǎn)換為數(shù)值瓶蚂;
  • 如果一個操作數(shù)是對象,另一個操作數(shù)不是宣吱,則調(diào)用對象的 valueOf() 方法窃这,用得到的基本類型值按照前面的規(guī)則進行比較;
  • null 和 undefined 是相等的征候。在比較相等性之前杭攻,不能將 null 和 undefined 轉(zhuǎn)換成其他任何值。
  • 如果有一個操作數(shù)是 NaN疤坝,則相等操作符返回 false兆解,而不相等操作符返回 true;
  • 如果兩個操作數(shù)都是對象跑揉,則比較它們的指針地址锅睛。如果都指向同一個對象,則相等操作符返回 true历谍;否則现拒,返回 false。

===!== 操作符最在比較之前不轉(zhuǎn)換操作數(shù)

  • ===: 類型相同望侈,并且值相等印蔬,才返回 true ,否則返回 false 脱衙。
  • !==: 類型不同侥猬,或者值不相等例驹,就返回 true,否則返回 false 陵究。

4.3.3 邏輯操作符: &&眠饮,||奥帘,!

邏輯與 && 和 邏輯或 || 返回的不一定是布爾值铜邮,而是包含布爾值在內(nèi)的任意類型值。

邏輯操作符屬于短路操作符 寨蹋。在進行計算之前松蒜,會先通過 Boolean() 方法將兩邊的分項轉(zhuǎn)換為布爾值,然后分別遵循下列規(guī)則進行計算:

  • &&:從左到右檢測每一個分項已旧,返回第一個布爾值為 false 的分項秸苗,并停止檢測 。如果沒有檢測到 false 項运褪,則返回最后一個分項惊楼。
  • ||:從左到右檢測每一個分項,返回第一個布爾值為 true 的分項秸讹,并停止檢測 檀咙。如果沒有檢測到 true 項,則返回最后一個分項璃诀。

布爾操作符 ! 其求值過程如下

  1. 對分項求值弧可,得到一個任意類型值;
  2. 使用 Boolean() 把該值轉(zhuǎn)換為布爾值 true 或 false劣欢;
  3. 對布爾值取反棕诵,即 true 變 false,false 變 true

利用 ! 的取反的特點凿将,使用 !! 可以很方便的將一個任意類型值轉(zhuǎn)換為布爾值

4.3.4 條件語句:if校套,while,?

  1. 對表達式求值牧抵,得到一個任意類型值
  2. 使用 Boolean() 將得到的值轉(zhuǎn)換為布爾值 true 或 false

5. String

5.1 語義

String 類型是零個或多個 16 位無符號整數(shù)值(“元素”)的所有有序序列的集合笛匙,最大長度為 2^53-1 個元素。 String 類型通常用于表示正在運行的程序中的文本數(shù)據(jù)灭忠,在這種情況下膳算,String 中的每個元素都被視為 UTF-16 代碼單元值。每個元素被視為占據(jù)序列內(nèi)的位置弛作。這些位置用非負整數(shù)索引涕蜂。第一個元素(如果有)位于索引 0,索引為 1 的下一個元素(如果有)映琳,依此類推机隙。 String 的長度是其中的元素數(shù)(即 16 位值)蜘拉。

5.2 Unicode

現(xiàn)行的字符集國際標準,字符是以 Unicode 的方式表示的有鹿,每一個 Unicode 的碼點表示一個字符旭旭,理論上, Unicode 的范圍是無限的。UTF 是 Unicode 的編碼方式葱跋,規(guī)定了碼點在計算機中的表示方法持寄,常見的有 UTF16 和 UTF8。 Unicode的碼點通常用 U+??? 來表示娱俺,其中 ??? 是十六進制的碼點值稍味。 0-65536(U+0000 - U+FFFF)的碼點被稱為基本字符區(qū)域(BMP)。

UTF-16 比較好理解,就是任何字符對應(yīng)的數(shù)字都用兩個字節(jié)來保存.我們通常對 Unicode 的誤解就是把 Unicode 與 UTF-16 等同了.但是很顯然如果都是英文字母這做有點浪費.明明用一個字節(jié)能表示一個字符為啥整兩個啊.

于是又有個 UTF-8,這里的 8 非常容易誤導人,8 不是指一個字節(jié),難道一個字節(jié)表示一個字符?實際上不是.當用 UTF-8 時表示一個字符是可變的,有可能是用一個字節(jié)表示一個字符,也可能是 兩個,三個.當然最多不能超過 3個字節(jié)了.反正是根據(jù)字符對應(yīng)的數(shù)字大小來確定.

于是 UTF-8 和 UTF-16 的優(yōu)劣很容易就看出來了.如果全部英文或英文與其他文字混合,但英文占絕大部分,用 UTF-8 就比 UTF-16 節(jié)省了很多空間.而如果全部是中文這樣類似的字符或者混合字符中中文占絕大多數(shù). UTF-16 就占優(yōu)勢了,可以節(jié)省很多空間.

來源

5.3 String 對象

在 JavaScript 中荠卷,字符串是基本數(shù)據(jù)類型模庐,本身不存任何操作方法 。為了方便的對字符串進行操作油宜,JavaScript 提供了一個 String 類型對象:String 對象 掂碱。它是一種特殊的引用類型,JS 引擎每當讀取一個字符串的時候慎冤,就會在內(nèi)部創(chuàng)建一個對應(yīng)的 String 對象疼燥,該對象提供了很多操作字符的方法,這就是為什么能對字符串調(diào)用方法的原因 粪薛。

5.4 String 對象的常見方法

  • 字符操作:charAt悴了,charCodeAt,fromCharCode
  • 字符串提任ナ佟:substr湃交,substring ,slice
  • 位置索引:indexOf 藤巢,lastIndexOf
  • 大小寫轉(zhuǎn)換:toLowerCase搞莺,toUpperCase
  • 模式匹配:match,search掂咒,replace才沧,split
  • 其他操作:concat,trim绍刮,localeCompare

charCodeAt 的作用是獲取字符的 Unicode 編碼温圆,俗稱 “Unicode 碼點”。通過 charCodeAt 獲取字符的 Unicode 編碼孩革,然后再把這個編碼轉(zhuǎn)化成二進制岁歉,就可以得到該字符的二進制表示。

var a = 'a';
var code = a.charCodeAt(0); // 97
code.toString(2); // 1100001

fromCharCode 是 String 對象上的靜態(tài)方法膝蜈,作用是根據(jù) Unicode 編碼返回對應(yīng)的字符锅移。

substring(start [, end])

substring 截取字符串的某個 start 位置到某個 end 位置(但 end 位置的字符不包括在結(jié)果中)的子串熔掺,如果沒有第 2 個 end 參數(shù),直到字符串末尾非剃。參數(shù)只接受正數(shù)和 0置逻,把負數(shù)或其它無效的數(shù)當作 0。

substr(start [, length])

substr 截取字符串的某個 start 位置起备绽,數(shù) length 個長度的字符才結(jié)束券坞。如果沒有第 2 個參數(shù),直到字符串末尾疯坤”剑可以接受 “負數(shù)”,表示從字符串尾部開始計數(shù)压怠。

slice(start [, end])

slice 與 substring 基本相同,不同的是參數(shù)能接受 “負數(shù)”飞苇,表示從結(jié)尾開始計數(shù)菌瘫。

6. Number

6.1 表示方式

JavaScript 中的數(shù)字類型只有 Number 一種,Number 類型采用 IEEE754 標準中的 “雙精度浮點數(shù)” 來表示一個數(shù)字布卡,不區(qū)分整數(shù)和浮點數(shù) 雨让。所以,1與1.0是相同的忿等,是同一個數(shù)栖忠。

6.2 存儲方式

在 IEEE754 中,雙精度浮點數(shù)采用 64 位存儲贸街,即 8 個字節(jié)表示一個浮點數(shù) 庵寞。其存儲結(jié)構(gòu)如下圖所示:

image

指數(shù)位可以通過下面的方法轉(zhuǎn)換為使用的指數(shù)值:

image

6.3 數(shù)值范圍

從存儲結(jié)構(gòu)中可以看出, 指數(shù)部分的長度是11個二進制薛匪,即指數(shù)部分能表示的最大值是 2047(211-1)捐川,取中間值進行偏移,用來表示負指數(shù)逸尖,也就是說指數(shù)的范圍是 [-1023,1024] 古沥。因此,這種存儲結(jié)構(gòu)能夠表示的數(shù)值范圍為 21024 到 2-1023 娇跟,超出這個范圍的數(shù)無法表示 岩齿。21024 和 2-1023 轉(zhuǎn)換為科學計數(shù)法如下所示:

1.7976931348623157 × 10308

5 × 10-324

因此,JavaScript 中能表示的最大值是 1.7976931348623157 × 10308苞俘,最小值為 5 × 10-324 盹沈。分別對應(yīng) Number 對象的 MAX_VALUE 屬性和 MIN_VALUE 屬性。

如果一個數(shù)大于等于 2 的 1024 次方苗胀,那么就會發(fā)生“正向溢出”襟诸,即 JavaScript 無法表示這么大的數(shù)瓦堵,這時就會返回 Infinity。

如果一個數(shù)小于等于 2 的 -1075 次方(指數(shù)部分最小值 -1023歌亲,再加上小數(shù)部分的 52 位)菇用,那么就會發(fā)生為“負向溢出”,即 JavaScript 無法表示這么小的數(shù)陷揪,這時會直接返回 0惋鸥。

6.4 精度丟失

計算機中的數(shù)字都是以二進制存儲的,如果要計算 0.1 + 0.2 的結(jié)果悍缠,計算機會先把 0.1 和 0.2 分別轉(zhuǎn)化成二進制卦绣,然后相加,最后再把相加得到的結(jié)果轉(zhuǎn)為十進制 飞蚓。

但有一些浮點數(shù)在轉(zhuǎn)化為二進制時滤港,會出現(xiàn)無限循環(huán) 。這時候為了表示該數(shù)會最末尾出進行 0 舍 1 入趴拧。最終導致精度丟失溅漾。

因此非整數(shù)的 Number 類型無法用 =====也不行) 來比較,因為有可能會發(fā)生精度丟失著榴。

精度丟失解決:正確的比較浮點數(shù)的方法是添履,檢查等式左右兩邊差的絕對值是否小于最小精度。

console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);  // true

6.5 特殊數(shù)值

  • Number.MAX_VALUE:JavaScript 中的最大值
  • Number.MIN_VALUE:JavaScript 中的最小值
  • Number.MAX_SAFE_INTEGER:最大安全整數(shù)脑又,為 253-1
  • Number.MIN_SAFE_INTEGER:最小安全整數(shù)暮胧,為 -(253-1)(在安全整數(shù)范圍內(nèi)不會出現(xiàn)精度丟失(小數(shù)除外))
  • Number.POSITIVE_INFINITY:對應(yīng) Infinity,代表正無窮
  • Number.NEGATIVE_INFINITY:對應(yīng) -Infinity问麸,代表負無窮
  • Number.EPSILON:是一個極小的值往衷,用于檢測計算結(jié)果是否在誤差范圍內(nèi)
  • Number.NaN:表示非數(shù)字,NaN 與任何值都不相等口叙,包括 NaN 本身
  • Infinity:表示無窮大炼绘,分 正無窮 Infinity 和 負無窮 -Infinity

指數(shù)部分為 2^11 – 1 且小數(shù)部分全 0,這個數(shù)字是 ±∞妄田。(符號位決定正負俺亮,代表正無窮 Infinity 和 負無窮 -Infinity)

指數(shù)部分為 2^11 – 1 且小數(shù)部分非全 0,這個數(shù)字是 NaN疟呐。它不是一個值脚曾,而是一批值。這也就解釋了為什么 NaN != NaN启具。

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

6.6.1 Number()

對于不同數(shù)據(jù)類型的轉(zhuǎn)換本讥,Number() 的處理也不盡相同,其轉(zhuǎn)換規(guī)則如下:

  • 如果是 Boolean 值,true 和 false 將分別被轉(zhuǎn)換為 1 和 0拷沸。
  • 如果是數(shù)字值色查,只是簡單的傳入和返回。
  • 如果是 null 值撞芍,返回 0秧了。
  • 如果是 undefined,返回 NaN序无。
  • 如果是字符串验毡,遵循下列規(guī)則:
    • 如果字符串中只包含數(shù)字(包括前面帶正號或負號的情況),則將其轉(zhuǎn)換為十進制數(shù)值;
    • 如果字符串中包含有效的浮點格式帝嗡,則將其轉(zhuǎn)換為對應(yīng)的浮點數(shù)值;
    • 如果字符串中包含有效的十六進制格式晶通,則將其轉(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)換返回的字符串值。

6.6.2 parseInt() 和 parseFloat()

parseInt() 只支持 16 進制的前綴 “0x”, 不支持其他進制尊剔。而且會忽略非數(shù)字字符爪幻。

parseFloat() 直接把原字符串作為十進制來解析。

他們都不支持科學計數(shù)法表示的字符串须误。

7. Symbol

7.1 語義

Symbol 是 ES6 新增的一種原始數(shù)據(jù)類型挨稿,它的字面意思是:符號、標記京痢。代表獨一無二的值 奶甘。

7.2 初始化

和其他基本類型不同的是,Symbol 作為基本類型祭椰,沒有對應(yīng)的包裝類型臭家,也就是說 Symbol 本身不是對象,而是一個函數(shù)方淤。因此钉赁,在生成 Symbol 類型值的時候,不能使用 new 操作符 携茂。

Symbol 函數(shù)可以接受一個字符串作為參數(shù)你踩,表示對 Symbol 值的描述,當有多個 Symbol 值時,比較容易區(qū)分带膜。

有時吩谦,我們希望重新使用同一個 Symbol 值,Symbol.for 方法可以做到這一點膝藕。它接受一個字符串作為參數(shù)式廷,然后全局搜索有沒有以該參數(shù)作為名稱的 Symbol 值。如果有束莫,就返回這個 Symbol 值懒棉,否則就新建并返回一個以該字符串為名稱的 Symbol 值。

Symbol.for() 也可以生成 Symbol 值览绿,它 和 Symbol() 的區(qū)別是:

  • Symbol.for() 首先會在全局環(huán)境中查找給定的 key 是否存在策严,如果存在就返回,否則就創(chuàng)建一個以 key 為標識的 Symbol 值
  • Symbol.for() 生成的 Symbol 會登記在全局環(huán)境中供搜索饿敲,而 Symbol() 不會妻导。
  • Symbol.for() 永遠搜索不到 用 Symbol() 產(chǎn)生的值。

7.3 Symbol 特性

Symbol 作為屬性名怀各,該屬性不會出現(xiàn)在 for...in倔韭、for...of 循環(huán)中,也不會被 Object.keys()瓢对、Object.getOwnPropertyNames()寿酌、JSON.stringify() 返回。但是硕蛹,它也不是私有屬性醇疼,有一個 Object.getOwnPropertySymbols() 方法,專門獲取指定對象的所有 Symbol 屬性名法焰。

8. Object

8.1 語義

ECMA262 把對象定義為:無序?qū)傩缘募涎砭#鋵傩钥梢园局怠ο蠡蛘吆瘮?shù)埃仪。

8.2 對象拷貝

由于引用類型的變量只存指針乙濒,而對象本身存儲在堆中 。因此卵蛉,當把一個對象賦值給多個變量時颁股,就相當于把同一個對象地址賦值給了每個變量指針 。這樣毙玻,每個變量都指向了同一個對象豌蟋,當通過一個變量修改對象,其他變量也會同步更新桑滩。

8.2.1 淺拷貝

ES6 提供了一個原生方法用于對象的拷貝梧疲,即 Object.assign() 允睹。

需要注意的是,Object.assign() 拷貝的是屬性值幌氮。當屬性值是基本類型時缭受,沒有什么問題 ,但如果該屬性值是一個指向?qū)ο蟮囊酶没ィ仓荒芸截惸莻€引用值米者,而不會拷貝被引用的那個對象。

8.2.2 深拷貝

深拷貝指的是徹底的拷貝一個對象作為副本宇智,兩者之間的操作相互不受影響蔓搞,可以通過 JSON 的序列化和反序列化方法來實現(xiàn) 。

9. 類型轉(zhuǎn)化

9.1 裝箱和拆箱

了解裝箱拆箱之前需要先了解包裝類型随橘。

Number喂分、String、Boolean机蔗、Symbol 這些基本類型都有對應(yīng)的包裝類型蒲祈。我們使用這些基本類型調(diào)用方法的時候,就會自動進行裝箱和拆箱操作萝嘁。

基本包裝類型是一種特殊的引用類型梆掸。它和普通引用類型有一個很重要的區(qū)別,就是對象的生存期不同 牙言。使用 new 操作符創(chuàng)建的引用類型的實例酸钦,在執(zhí)行流離開當前作用域之前都一直保存在內(nèi)存中。而自動創(chuàng)建的基本包裝類型的對象咱枉,則只存在于一行代碼的執(zhí)行瞬間钝鸽,然后立即被銷毀。

9.1.1 裝箱轉(zhuǎn)換:把基本類型轉(zhuǎn)換為對應(yīng)的包裝類型

裝箱轉(zhuǎn)換會在我們利用基本類型調(diào)用方法的時候自動發(fā)生庞钢。

使用內(nèi)置的 Object 函數(shù),我們可以在 JavaScript 代碼中顯式調(diào)用裝箱能力因谎。

    var symbolObject = Object(Symbol("a"));

    console.log(typeof symbolObject); //object
    console.log(symbolObject instanceof Symbol); //true
    console.log(symbolObject.constructor == Symbol); //true

裝箱機制會頻繁產(chǎn)生臨時對象基括,在一些對性能要求較高的場景下,我們應(yīng)該盡量避免對基本類型做裝箱轉(zhuǎn)換财岔。

9.1.2 拆箱操作:把引用類型轉(zhuǎn)換為基本類型

從引用類型到基本類型的轉(zhuǎn)換风皿,也就是拆箱的過程中,會遵循 ECMAScript 規(guī)范規(guī)定的 toPrimitive 原則匠璧,一般會調(diào)用引用類型的 valueOf 和 toString 方法桐款,你也可以直接重寫 toPeimitive 方法。一般轉(zhuǎn)換成不同類型的值遵循的原則不同夷恍,例如:

  • 引用類型轉(zhuǎn)換為 Number 類型魔眨,先調(diào)用 valueOf,再調(diào)用 toString
  • 引用類型轉(zhuǎn)換為 String 類型,先調(diào)用 toString遏暴,再調(diào)用 valueOf

若valueOf和toString都不存在侄刽,或者沒有返回基本類型,則拋出TypeError異常朋凉。

我們可以直接調(diào)用包裝類型的valueOf或toString州丹,實現(xiàn)拆箱操作。

9.2 隱式類型轉(zhuǎn)換

9.2.1 規(guī)則

image

9.2.2 各種運算符

我們在對各種非 Number 類型運用數(shù)學運算符 (- * /) 時杂彭,會先將非Number類型轉(zhuǎn)換為 Number 類型;

注意 + 是個例外墓毒,執(zhí)行 + 操作符時:

  • 1.當一側(cè)為 String 類型,被識別為字符串拼接亲怠,并會優(yōu)先將另一側(cè)轉(zhuǎn)換為字符串類型所计。
  • 2.當一側(cè)為 Number 類型,另一側(cè)為原始類型赁炎,則將原始類型轉(zhuǎn)換為 Number 類型醉箕。
  • 3.當一側(cè)為 Number 類型,另一側(cè)為引用類型徙垫,將引用類型和 Number 類型轉(zhuǎn)換成字符串后拼接讥裤。

其他運算符涉及的類型轉(zhuǎn)換可以查看上面 4.3 的相關(guān)總結(jié)。

10. 判斷數(shù)據(jù)類型

10.1 typeof

typeof 是一個操作符姻报,其右側(cè)跟一個一元表達式己英,并返回這個表達式的數(shù)據(jù)類型。返回的結(jié)果用該類型的字符串(全小寫字母)形式表示吴旋。

有些時候损肛,typeof 操作符會返回一些令人迷惑但技術(shù)上卻正確的值:

  • 對于基本類型,除 null 以外荣瑟,均可以返回正確的結(jié)果治拿。
  • 對于引用類型,除 function 以外笆焰,一律返回 object 類型。
  • 對于 null 嚷掠,返回 object 類型狠轻。
  • 對于 function 返回 function 類型檐蚜。

對于 null 來說這屬于最初的設(shè)計缺陷導致的。

10.2 instanceof

instanceof 是用來判斷 A 是否為 B 的實例鲫骗,表達式為:A instanceof B悲雳,如果 A 是 B 的實例挎峦,則返回 true,否則返回 false坦胶。

instanceof 只能用來判斷兩個對象是否屬于實例關(guān)系, 而不能判斷一個對象實例具體屬于哪種類型晴楔。

instanceof 操作符的還有一個問題就是:它假定只有一個全局執(zhí)行環(huán)境顿苇。如果網(wǎng)頁中包含多個框架,那實際上就存在兩個以上不同的全局執(zhí)行環(huán)境税弃,從而存在兩個以上不同版本的構(gòu)造函數(shù)纪岁。如果你從一個框架向另一個框架傳入一個數(shù)組,那么傳入的數(shù)組與在第二個框架中原生創(chuàng)建的數(shù)組分別具有各自不同的構(gòu)造函數(shù)则果,這時候 instanceof 就會返回 false幔翰。

10.3 toString

toString() 是 Object 的原型方法,調(diào)用該方法西壮,默認返回當前對象的 [[Class]] 遗增。這是一個內(nèi)部屬性,其格式為 [object Xxx] 款青,其中 Xxx 就是對象的類型做修。

對于 Object 對象,直接調(diào)用 toString() 就能返回 [object Object] 抡草。而對于其他對象饰及,則需要通過 call / apply 來調(diào)用才能返回正確的類型信息。

Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]

這種方式是被很多人推薦使用的康震。

11. 參考

  1. 細說 JavaScript 七種數(shù)據(jù)類型
  2. 【JS 進階】你真的掌握變量和類型了嗎
  3. JS 教程
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末燎含,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子腿短,更是在濱河造成了極大的恐慌瘫镇,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件答姥,死亡現(xiàn)場離奇詭異,居然都是意外死亡谚咬,警方通過查閱死者的電腦和手機鹦付,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來择卦,“玉大人敲长,你說我怎么就攤上這事郎嫁。” “怎么了祈噪?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵泽铛,是天一觀的道長。 經(jīng)常有香客問我辑鲤,道長盔腔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任月褥,我火速辦了婚禮弛随,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宁赤。我一直安慰自己舀透,他們只是感情好,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布决左。 她就那樣靜靜地躺著愕够,像睡著了一般。 火紅的嫁衣襯著肌膚如雪佛猛。 梳的紋絲不亂的頭發(fā)上惑芭,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機與錄音挚躯,去河邊找鬼强衡。 笑死,一個胖子當著我的面吹牛码荔,可吹牛的內(nèi)容都是我干的漩勤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼缩搅,長吁一口氣:“原來是場噩夢啊……” “哼越败!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起硼瓣,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤究飞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后堂鲤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亿傅,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年瘟栖,在試婚紗的時候發(fā)現(xiàn)自己被綠了葵擎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡半哟,死狀恐怖酬滤,靈堂內(nèi)的尸體忽然破棺而出签餐,到底是詐尸還是另有隱情,我是刑警寧澤盯串,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布氯檐,位于F島的核電站,受9級特大地震影響体捏,放射性物質(zhì)發(fā)生泄漏冠摄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一译打、第九天 我趴在偏房一處隱蔽的房頂上張望耗拓。 院中可真熱鬧,春花似錦奏司、人聲如沸乔询。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽竿刁。三九已至,卻和暖如春搪缨,著一層夾襖步出監(jiān)牢的瞬間食拜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工副编, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留负甸,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓痹届,卻偏偏與公主長得像呻待,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子队腐,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345