原文: https://zswfx.com/articles/5dc8f64a9cf7c17b240e5c6c
我們經常在函數參數裏面使用如下操作 Array.prototype.slice.call(arguments, 1), 這樣的操作,類似還有 Object.prototype.toString.apply(o)這種操作,為什麼可以這樣玩呢?
前言
我們經常通過數組的方法去操作類數組,還會使用一些JS對象的方法來獲取一個對象的真實的構造函數對象名稱。考慮類數組不是一個數組,是一個對象類似如下:
{
"0": "b",
"1": "a",
"length": 2
}
這樣就可以使用,為什麼呢?
探索
為了搞清上面問題,我們就需要從兩個方面入手:
- call/apply 定義
- Array.prototype.slice、Object.prototype.toString
第一個需要找一下call/apply 調用流程,第二個看看規範如何定義這些方法
就已apply 為例(call類似), 具體方法以slice和toString為例
apply 規範
使用apply方法,有兩個作用
- 1-8 處理通過 apply 方法傳入的參數
- 9 處理改變函數的this值,並調用函數
上面調用函數,我們接下來就繼續看看函數如何處理
Array.prototype.slice
通過規範可以看出,Array也是通過key值獲取的,在第10步中可以看到循環獲取對象值,通過對象 [[Get]]的方式來獲取。
在每個數組方法後面,我們可以看到這樣一句話:
使用數組的所有方法,不一定要求對象是數組,只要符合能夠通過遞增的key值可以獲取的類數組對象即可使用.
下面繼續看看 toString
toString
我們正常使用 Object.prototype.toString.apply({}) 的結果是 [object Object]. 上面是規範結果
- 第1步,確定 undefined 值為
[object Undefined] - 第2步,確定 null 值為
[object Null], - 第3步,通過內部方法
toObject得到結果 (稍後説明toObject方法) - 第4步,獲取內部
[[Class]]值 - 第5步,拼接字符串
[object、[[Class]],]返回結果
由此可得知,我們得到結果其實也是引擎根據規範來處理的。
toObject
![]()
toObject 的結果就是返回原始值(Primive Value)的盒裝對象(box model object).
最後 [[Class]]的獲取結果是一個説明對象分類名稱的字符串。
最後
最近探索規範,發現越來越多想法和只是和規範一一驗證。探索規範過程也是一種進步過程,任何小的改變,都是有跡可循,任何東西都來自規範。正如有理論支持的代碼,才是堅不可摧,否則就如同一盤散沙。
歡迎交流.