【JS迷你書】類型轉換之裝箱操做

衆所周知,JS 是一門弱類型語言。它不須要事先具體聲明變量的類型,由於會在程序運行過程當中,類型會被自動推斷肯定。所以,能夠用同一個變量保存不一樣類型的數據:javascript

var a = 1;
a = 'abc';
a = {
  x1
};
複製代碼

JS中目前共有7種數據類型:UndefinedNullBooleanNumberStringSymbolObjectjava

前 6 者是基本類型數據,Object 是引用類型數據。git

兩者有什麼區別呢?github

變量保存基本類型數據時,是直接棧內保存的,而引用類型是在堆中生成,在棧內保存的是該對象的引用。app

除此以外,還有一點不一樣就是:基本類型數據自己不可變,但引用類型數據是可變的。函數

引用類型數據是可變的,不言而喻,是指咱們能夠修改其屬性值。ui

var a = {
  x1
};
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:

  1. Evaluate MemberExpression.
  2. Call GetValue(Result(1)).
  3. Evaluate Expression.
  4. Call GetValue(Result(3)).
  5. Call ToObject(Result(2)).
  6. Call ToString(Result(4)).
  7. Return a value of type Reference whose base object is Result(5) and whose property name is Result(6).

它是以「[]」屬性訪問方式爲例來講明的。

這裏再具體舉一個例子,來看看整個流程。好比,a = 1,而後獲取 a['x'] 。

  1. 計算表達式 a。(這裏用表達式是考慮到像這種情形:a.b['x'],此時表達式是 a.b)
  2. 獲取上一步結果的值,這裏是1。
  3. 計算表達式 'x'。(這裏用表達式是考慮到像這種情形:a['x'+'y'],此時表達式 'x'+'y')
  4. 獲取第 3 步的結果,即 'x'。
  5. 把第 2 步的結果傳入 ToObject,即 ToObject(1)。這裏記作 temp(能夠看出這一步是關鍵。)
  6. 把第 4 步,轉化爲字符串,固然仍是 'x'
  7. 返回,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).

與咱們預知的同樣,布爾、數值和字符串這三種類型都生成相應的對象實例。而對象類型,直接返回自己。另外,UndefinedNull 類型是報錯的。

至此,JS 的「裝箱」操做說完了。

感謝你的閱讀。

本文完。

《JavaScript 迷你書》傳送門,全面夯實基礎

掘金收藏

相關文章
相關標籤/搜索