JavaScript進階系列04,函數參數個數不確定情況下的解決方案



本篇主要體驗函數參數個數不確定情況下的一個解決方案。先來看一段使用函數作為參數進行計算的實例。

        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進階系列”包括:

JavaScript進階系列01,函數的聲明,函數參數,函數閉包

JavaScript進階系列02,函數作為參數以及在數組中的應用

JavaScript進階系列03,通過硬編碼、工廠模式、構造函數創建JavaScript對象

JavaScript進階系列04,函數參數個數不確定情況下的解決方案

JavaScript進階系列05,事件的執行時機, 使用addEventListener為元素同時注冊多個事件,事件參數

JavaScript進階系列06,事件委托

JavaScript進階系列07,鼠標事件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM