衆所周知,JS 是一門弱類型語言。它不須要事先具體聲明變量的類型,由於會在程序運行過程當中,類型會被自動推斷肯定。所以,能夠用同一個變量保存不一樣類型的數據:javascript
var a = 1;
a = 'abc';
a = {
x: 1
};
複製代碼
JS中目前共有7種數據類型:Undefined
、Null
、Boolean
、Number
、String
、Symbol
和 Object
。java
前 6 者是基本類型數據,Object
是引用類型數據。git
兩者有什麼區別呢?github
變量保存基本類型數據時,是直接棧內保存的,而引用類型是在堆中生成,在棧內保存的是該對象的引用。app
除此以外,還有一點不一樣就是:基本類型數據自己不可變,但引用類型數據是可變的。函數
引用類型數據是可變的,不言而喻,是指咱們能夠修改其屬性值。ui
var a = {
x: 1
};
a.x = 2
console.log(a); // => {x: 2}
console.log(a.x); // 2
複製代碼
a.x 或者 a['x'] 中「.」和「[]」操做符是專門用來獲取引用類型屬性值的。然而在 JS 中基本類型變量也是可使用「點」的,這給初學者形成必定困惑,好比:lua
var a = 1;
a.x = 2;
console.log(a);// 1
console.log(a.x);// undefined
複製代碼
其實,上述代碼運行過程當中發生了所謂的「裝箱」操做。spa
好比第二行:3d
a.x = 2
複製代碼
等價於:
var temp = new Number(a)
temp.x = 2
temp = null
複製代碼
由於 2 是基本類型,在取其屬性時,先用對應的 Number
構造函數包裹成一個臨時對象,而後再對臨時對象取屬性值操做,隨後這個臨時對象便銷燬。
整個過程稱爲「裝箱」。知道這個過程後,那麼整段代碼就好理解了:
var a = 1;
var temp1 = new Number(a);
temp1.x = 2;
temp1 = null;
console.log(a);// 1
var temp2 = new Number(a);
console.log(temp2.x);// undefined
temp2 = null;
複製代碼
看到了嗎,兩次 a.x
,有兩次「裝箱」,所以是兩個不一樣的臨時對象。給一個對象存值,而後再去另一個對象那裏取值,必然是取不到的。
「裝箱」這種說法是來自其餘語言的。其實叫啥名字可有可無,主要是理解這個過程,再也不迷糊。
接下來的內容,咱們準備去看看 JS 文檔規範裏是怎麼描述的這個問題的。
爲了方便,咱們看第 3 版就行,即《ECMA-262 3rd edition》。該規範比較早,固然也能夠看最新的。
其中第 44 頁,第 11.2.1 小節,對屬性訪問器(Property Accessors)描述以下:
The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:
- Evaluate MemberExpression.
- Call GetValue(Result(1)).
- Evaluate Expression.
- Call GetValue(Result(3)).
- Call ToObject(Result(2)).
- Call ToString(Result(4)).
- Return a value of type Reference whose base object is Result(5) and whose property name is Result(6).
它是以「[]」屬性訪問方式爲例來講明的。
這裏再具體舉一個例子,來看看整個流程。好比,a = 1,而後獲取 a['x'] 。
- 計算表達式 a。(這裏用表達式是考慮到像這種情形:a.b['x'],此時表達式是 a.b)
- 獲取上一步結果的值,這裏是1。
- 計算表達式 'x'。(這裏用表達式是考慮到像這種情形:a['x'+'y'],此時表達式 'x'+'y')
- 獲取第 3 步的結果,即 'x'。
- 把第 2 步的結果傳入 ToObject,即 ToObject(1)。這裏記作 temp(能夠看出這一步是關鍵。)
- 把第 4 步,轉化爲字符串,固然仍是 'x'
- 返回,temp['x']。
其中第 5 步,最爲關鍵。它用 ToObject 生成個臨時對象(由於它只是局部變量),咱們最後取到的屬性值正是這個對象的屬性值。
ToObject
(第 48 頁)操做具體爲:
Input | Type Result |
---|---|
Undefined | Throw a TypeError exception. |
Null | Throw a TypeError exception. |
Boolean | Create a new Boolean object whose [[value]] property is set to the value of the boolean. See 15.6 for a description of Boolean objects. |
Number | Create a new Number object whose [[value]] property is set to the value of the number. See 15.7 for a description of Number objects. |
String | Create a new String object whose [[value]] property is set to the value of thestring. See 15.5 for a description of String objects. |
Object | The result is the input argument (no conversion). |
與咱們預知的同樣,布爾、數值和字符串這三種類型都生成相應的對象實例。而對象類型,直接返回自己。另外,Undefined
和 Null
類型是報錯的。
至此,JS 的「裝箱」操做說完了。
感謝你的閱讀。
本文完。