爲何arguments是類數組對象

爲何JavaScript裏函數的arguments只是array-like object?

只是標準這麼規定的,仍是有什麼設計緣由在裏面?

JavaScript的函數裏面的arguments對象有 .lengh 屬性和能夠經過 [] 訪問,可是確實從Object.prototype繼承的。不少時候都會用 Array.prototype.slice.call(arguments) 或者 Array.from(arguments) 轉成數組。直接設計成數組不是更好嗎?

 

 

這個問題又激起了個人八卦之心!react

在一番尋找以後,找到了彷佛是目前網上僅存的 Brendan Eich 本人探討 arguments 的資料,是一份錄音: (來自 aminutewithbrendan.com 這個已經被關閉的網站,彷佛是和當時的贊助事件調查有關因此被關掉了,可是 archive.org 有存檔哈哈)web

大體上,BE 本人也認可 arguments 的設計是由於當時只花了十天因此整得太糙了。在正式規範化 JavaScript 的時候,Microsoft 曾經有人提出把 arguments 改爲真正的 Array,BE 本人甚至都打算動手改實現了,可是 MS 那邊回去商量了下又回來以爲多一事不如少一事,不改了。因而這個糟糕的設計就今後成爲了規範... 這是 1997 年的初版 ES 規範。數組

除了 arguments.callee 以外,還有一個神奇的 quirk,那就是 arguments 和實際的參數變量之間的迷之綁定。規範裏是這麼說的:less

In the case when iarg is less than the number of formal parameters for the function object, this property shares its value with the corresponding property of the activation object. This means that changing this property changes the corresponding property of the activation object and vice versa. The value sharing mechanism depends on the implementation.

換言之,假設一個函數的第一個參數是 a,當你修改 a 的值的時候,arguments[0] 也會同步變化:ide

(function (a) { console.log(arguments[0] === a) // -> true console.log(a) // -> 1 // 修改 arguments arguments[0] = 10 console.log(a) // -> 10 // 修改參數變量 a = 20 console.log(arguments[0]) // -> 20 })(1,2) 

後面的事情你也知道了,ES 規範是要向後兼容的,並且上面的這個 quirk 使得它在引擎實現中須要不少特殊處理,一旦改動,兼容性影響巨大,因此它永遠也改不了了。聽說在 ES5 討論時也有人提出要把 arguments 改爲 Array 的 subclass,可是很快就不了了之,只是在 strict mode 下對 arguments.callee 和上面的綁定 quirk 進行了限制。直到 ES6 終於對 arguments 提供了一個替代品 - rest parameters:函數

 

function foo (...args) { // 這裏 args 終因而真正的 Array 了! } 
BE 本人並無提到爲何一開始會把 arguments 設計成對象,所以咱們也只能作猜想。但一個合理的推測是,ES1 裏面的 Array.prototype 其實很弱,只有四個方法:toString, join, reverse 和 sort - 連 push, pop, shift, unshift, splice 都沒有!而 forEach, filter, map, reduce 這些有用的方法更是 ES5 才添加進來的。因此當時 arguments 就算真的繼承自 Array 貌似也沒什麼大用,因此就這樣被放過了... 固然,這只是咱們的猜想,估計 BE 本身今天也說不清本身當時爲何這麼幹的了吧。
相關文章
相關標籤/搜索