本篇主要體驗函式引數個數不確定情況下的一個解決方案。先來看一段使用函式作為引數進行計算的例項。
var calculate = function(x, y, fn) {return fn(x, y);
};var sum = function(x, y) {return x + y;
};var diff = function(x, y) {return x - y;
};var sumResult = calculate(1, 2, sum),diffResult = calculate(1, 2, diff);
但是,以上有一個問題:彈性不夠好,如果caculate需要多個形參,我們可能這樣寫:
var calculate = function(x, y, z, a, b, c, fn){}
這樣,每次需求改變,都要更改這裡的引數,顯得非常不方便。
我們知道,不管函式有多少個引數,所有的引數都會被儲存到arguments到這個陣列型別中。試想一下,如果我們可以從argments陣列中拿到最後一個元素,即代表函式的fn,再把其它陣列元素作為fn的引數,執行fn(arguments),這樣,不管方法的引數列表有多長,都可以把所有引數放到argments中再傳遞給函式。
還記得Array有一個原型方法pop,能把陣列的最後一個元素彈出,如果能把這個方法應用到arguments上,不就可以拿到arguments的最後一個元素、fn函式了嗎?而實際上,JavaScript是允許把一個物件的方法應用到另外的物件上的!
先來熟悉一下如何使用吧。
□ 把一個物件的方法應用到另外一個物件
※ 不傳遞引數
var obj = {name: "myname",
doSth: function() {alert(this.name);
}};var foo = {name: "my name is foo"
};var bar = {name: "my name is bar"
};obj.doSth();
輸出結果:myname
如果我們想把obj物件的doSth方法應用到foo物件,可以使用apply方法,把最後一行改為:
obj.doSth.apply(foo);
輸出結果:my name is foo
※ 傳遞引數
如果obj物件的doSth方法帶引數,使用apply方法是否能把doSth方法的引數傳遞給foo或bar物件呢?
var obj = {name: "myname",
doSth: function(x, y) {alert(this.name + " " + x + " " + y);}};var foo = {name: "my name is foo"
};var bar = {name: "my name is bar"
};obj.doSth.apply(bar, ["hello", "world"]);
輸出結果:my name is bar hello world
可見,可以把doSth的引數以陣列的形式作為apply方法的實參,傳遞給bar物件。
※ 使用call方法
call方法也可以實現把一個物件的方法應用到另外一個物件。但用法和apply有所區別。
把最後一行程式碼改為:
obj.doSth.call(foo, "hello", "world");
輸出結果:my name is foo hello world
可見,doSth的引數挨個作為call方法的實參,傳遞給foo物件。
□ 程式碼改進
var calculate = function() {var fn = Array.prototype.pop.apply(arguments);return fn.apply(null, arguments);};var sum = function(x, y) {return x + y;
};var diff = function(x, y) {return x - y;
};var sumResult = calculate(1, 2, sum),diffResult = calculate(1, 2, diff);alert(sumResult);
在calculate方法中,首先把Array的原型方法pop應用到了argments上,這樣就拿到了引數列表中的最後一個函式,然後再把arguments陣列傳遞給fn.apply方法。注意:不能以fn(arguments)呼叫,因為arguments是陣列而不是引數列表。
再來修改sum方法和diff方法,讓它們可以處理多個引數。
var calculate = function() {var fn = Array.prototype.pop.apply(arguments);return fn.apply(null, arguments);};var sum = function() {var total = 0;for (var i = 0, l = arguments.length; i < l; i = i + 1) {
total = total + arguments[i];}return total;
};var diff = function () {//把Array獲取陣列第一個元素的shift方法應用到argments上
var total = Array.prototype.shift.apply(arguments);for (var i = 0, l = arguments.length; i < l; i = i + 1) {
total = total - arguments[i];}return total;
};var sumResult = calculate(1, 2, 3, 4, 5, sum),diffResult = calculate(5, 1, 2, diff);alert(sumResult);alert(diffResult);
輸出結果:
15
2
總結:
○ 當一個函式需要處理多個引數,並且最後一個引數是函式,類似someFucntion(引數1, 引數2......引數n, fn),我們可以先取出函式fn,再把引數1, 引數2......引數n以陣列形式傳遞給fn.apply(null,arguments)
○ 在JavaScript中,可以把一個物件的方法應用到另外的物件上
“JavaScript進階系列”包括: