神秘的論據對象賦值
上週,我發現了我認為是 Firefox 的 JavaScript 實現中的一個錯誤並提交了它。 Brendan Eich 的回應表明,有問題的行為實際上符合規範,並且已經實施了一段時間。我又進行了一些測試,試圖找出我哪裡出錯了。事實上,Firefox、Internet Explorer 和 Safari 都表現出相同的行為,而 Chrome 則沒有。這就是發生的事情。
代碼
有問題的代碼如下:
function doAdd(num1, num2) {
if(arguments.length == 1) {
arguments[1] = 10;
}
alert(arguments[0] + num2);
}
doAdd(10);
您期望底線輸出什麼?在 Chrome 中,它輸出 20,因為分配給 arguments[1]
也分配給 num2
.在其他瀏覽器中,它輸出 NaN
,因為分配給 arguments[1]
也不分配給 num2
.這裡到底發生了什麼?
規範
我的困惑源於 ECMA-262 第 5 版的第 10.6 節註釋 1,內容如下:
在回答 Baranovskiy 的 JavaScript 測驗時,我之前已經討論過類似的條款,至少是第 3 版。我以為我已經理解了 arguments
總是綁定到函數的命名參數。 Tom Schuster 和 Brendan Eich 都指出,早在 10.6 節中,在創建 arguments
的說明中 對象,出現以下內容:
因此,arguments 對像是根據傳遞給函數的實際參數的數量而不是根據為函數定義的命名參數的數量創建的。這意味著,正如 Tom 指出的,將為 arguments
的數字索引創建的 setter object 僅適用於實際傳入的參數數量。因此,在我的示例中,arguments[1]
成為 arguments
的直接屬性分配 對象而不是調用將值複製到命名參數的特殊設置器。
更多代碼
因此,即使我之前的示例不適用於所有瀏覽器,但這個示例可以:
function doAdd(num1, num2) {
arguments[1] = 10;
alert(arguments[0] + num2);
}
doAdd(10, 25); //20
此示例的最後一行在所有瀏覽器中輸出 20。由於我現在將兩個參數傳遞給函數,這意味著 arguments
使用兩個插槽創建對象,因此特殊設置器適用於索引 0 和 1。設置 arguments[1]
在這段代碼中實際上確實更新了 num2
並覆蓋傳入的值。
結論
規範難以理解,更難以實施。這只是一個微妙的提醒,即在 JavaScript 的黑暗角落裡有龍所在。不時戳戳龍並準確了解它們會做什麼是很有趣的。有時他們會燒死你,但無論哪種方式你都會學到。