本篇主要體驗函數參數個數不確定情況下的一個解決方案。先來看一段使用函數作為參數進行計算的實例。
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進階系列”包括: