2011-10-16 20 views
1

我想寫一個像jQuery這樣的函數,並使用javascript調用函數。Javascript調用類型

function each(array, callback) { 
    for (var i=0; i<array.length; i++) { 
     console.log(typeof(array[i])); // Number 
     callback.call(array[i]); 
    } 
} 

each([1,2,3], function() { 
    console.log(typeof(this)); // Object 
}); 

問題是調用似乎是將數字類型轉換爲對象類型。這會導致console.log調用出現問題。任何人都可以解釋爲什麼會發生這種情況(我的猜測是調用將參數轉換爲Object類型)。爲什麼會這樣做?你能想出一種解決方法或防止這種情況嗎?

回答

3

這是規範的要求在不嚴格模式

如果您在代碼的頂部使用"use strict";聲明,您將獲得您傳遞的任何實際值。

DEMO:http://jsfiddle.net/agXkZ/

"use strict"; 
function each(array, callback) { 
    for (var i=0; i<array.length; i++) { 
     callback.call(array[i]); 
    } 
} 

each([1,2,3], function() { 
    console.log(this); 
}); 

注意嚴格模式是詞法範圍,所以你可以聲明添加到回調只是如果你願意。

DEMO:http://jsfiddle.net/agXkZ/1/

function each(array, callback) { 
    for (var i=0; i<array.length; i++) { 
     callback.call(array[i]); 
    } 
} 

each([1,2,3], function() { 
    "use strict"; 
    console.log(this); 
}); 

如果你不想使用嚴格模式,你可以(在這種情況下)轉換爲原始使用一元+操作。

DEMO:http://jsfiddle.net/agXkZ/2/

function each(array, callback) { 
    for (var i=0; i<array.length; i++) { 
     callback.call(array[i]); 
    } 
} 

each([1,2,3], function() { 
    console.log(+this); // <--converts from object to primitive 
}); 

相關信息:

ECMAScript 5 Annex E (informative) Additions and Changes in the 5th Edition that Introduce Incompatibilities with the 3rd Edition

15.3.4.3,15.3.4.4:在第3版傳遞未定義作爲第一個參數要麼Function.prototype.applyFunction.prototype.call使全局對象要傳遞到間接調用目標函數作爲該值。如果第一個參數是原始值,則調用ToObject原始值的結果作爲此值傳遞。在第5版,這些轉換沒有被執行,實際的第一個參數值作爲這個值傳遞...

ECMAScript 5 Annex C (informative) The Strict Mode of ECMAScript:如果這是在嚴格模式代碼評估

,那麼這個值不會被強制轉換爲對象。 未定義不被轉換到全局對象原始值不被轉換爲包裝對象的此值。通過函數調用傳遞的值(包括使用Function.prototype.applyFunction.prototype.call進行的調用)的值不會強制傳遞給此對象的值。

+0

這很古怪,但它確實有效。謝謝! –

+0

@Ty .:不客氣。是的,這是不同的。嚴格模式是要走的路,但是您需要確保您爲不支持嚴格的瀏覽器正確處理值。無論哪種方式,回到原語的簡單方法是使用一元'+'運算符。 'console.log(+ this)'http://jsfiddle.net/agXkZ/2/ – user113716

2

call方法的第一個參數是必須執行回調的範圍。實際的論點只從第二個參數開始。這會工作

function each(array, callback) { 
    for (var i=0; i<array.length; i++) { 
     console.log(typeof(array[i])); // Number 
     callback.call(this, array[i]); 
    } 
} 

each([1,2,3], function() { 
    console.log(typeof(arguments[0])); // Number 
}); 

至於數量越來越轉換爲對象,MDN doc有解釋

第一個參數是爲調用樂趣this值。請注意,這可能是 不是該方法看到的實際值:如果該方法是非嚴格模式代碼中的 函數,則空值和未定義值將被替換爲全局對象,並且原始值將被裝箱。

在這種情況下,原始數字被裝箱。要看到拳擊在行動中,您可以運行此代碼。

function each(array, callback) { 
    for (var i=0; i<array.length; i++) { 
     console.log(typeof(array[i])); // Number 
     callback.call(array[i]); 
    } 
} 

each([1,2,3], function() { 
    console.log(typeof(this)); // Object 
    console.log(Number(this)); // prints 1,2 and 3 
}); 
+0

OP詢問爲什麼數字作爲回調的調用上下文從原語轉換爲對象傳遞。 – user113716

+0

明白了,相應更新。感謝您指出。 –

0

this意在用於引用功能是其一部分的對象。

儘管可以像使用自由參數那樣使用它,但通常只需將undefined作爲第一個參數傳遞給call並將該值作爲常規參數即可。內置的JavaScript中迭代函數(如Array的.forEach)設置this,並且它變得常見綁定功能

沒有一個特定的this值,這樣就可以訪問它,不管誰呼籲他們(.bind是部分的JavaScript 1.8.5,但有很多第三方庫都有自己的綁定工具,like Underscore)。如果我將約束函數傳遞到您的each(),它將無法看到當前對象!