當函數以 apply 方式調用時, 傳參方式是一個由各個參數組成的數組或類數組(一個有length屬性的對象),傳入參數個數取決於 length 的值,例如,某個對象 args.length=3; apply 會將 args[0],args[1],args[2] 三個參數傳入,如果對應的值不存在則傳入了undefined.
例如:
function f(a,b,c){ console.log(a,b,c);} f.apply(null,{0:123,1:456,2:789,length:2});//123 456 undefined ,因為 length 屬性值為2,值只傳入了 2 個參數 f.apply(null,{10:123,11:456,12:789,length:3});// undefined undefined undefined , 因為參數對象不存在以 0、1、2 為 key 的值
但是,在IE8 及低於IE8以下的瀏覽器需要注意幾個問題.
1、 apply 傳參不接受類似 {0:'a',1:'b',length:2} 的對象,可以是 數組、arguments、 HTMLCollection 對象 和 Nodelist 對象等節點集合.
在這種情況下你也許想要把傳參對象轉換成數組.
2、節點集合無法調用數組的原型方法,但是 類似 {0:'a',1:'b',length:2} 的對象可以。
var nodes = document.getElementsByTagName("div"); var obj = {0:1,1:2,2:3,length:3}; var args = Array.prototype.slice.apply(nodes,[0]); //error,"Array.prototype.slice: 'this' 不是 JavaScript 對象",節點集合無法調用數組原型的方法 var args = Array.prototype.slice.apply(obj,[0]); //ok var args = Array.prototype.concat.apply([],nodes); //ok var args = Array.prototype.concat.apply([],obj); //error,"Function.prototype.apply: 缺少 Array 或 arguments 對象",普通對象無法用於 apply 傳參
綜合以上,可以使用 try-catch
var nodes = document.getElementsByTagName("div"); var obj = {0:1,1:2,2:3,length:3}; var params = nodes;//try nodes and obj try{ var args = Array.prototype.slice.apply(params ,[0]); }catch(err){ var args = Array.prototype.concat.apply([],params); } console.log(args);
另外,也許有這樣的:
var args = Array.apply([],params);//應使用,Array.prototype.concat.apply([],params) var obj = {0:3,length:1}; var args = Array.apply([],obj); //在 obj[0] 符合數組 length 取值范圍時,將得到長度為3 的空數組而不是 [3],這種情況比較容易疏忽 args.length ;//3 ( obj[0]<Math.pow(2,32)-1)
關於 concat :
數組的 concat 方法 可以被任何對象調用,得到一個數組,但是, 如果調用者不是 數組, 那么 調用者本身 僅僅作為 結果數組的第一個元素
function f(a,b){ var args = [].concat.apply(arguments,[111,222,333]); console.log(args); console.log(args.length); console.log(args[0]); } f("x","y") //執行結果 [Arguments[2], 111, 222, 333] 4 ["x", "y"]