天天看點

Javascript 函數參數名妙用(區分函數參數名稱)

首先,我們看兩個函數

var perform1 = function (dog) {
            console.log(dog.name);
    };

var perform2 = function (cat) {
            console.log(cat.name);
    };
           

這兩個函數很難想象他們調用會有不一樣的效果,他們唯一的差別就是參數名稱的不同。然而很多流行的架構,你傳入的匿名函數,你自己都不知道參數應該是什麼,什麼順序,是以在大部分架構中就實作了根據參數名來指派的效果。

比如說,我們有一個Performance類,有個perform方法,而這個perform方法讓使用者自己定義。也就是說,使用者需要自己定義個函數,然後指派給Performance.perform.使用者想實作如下的功能:

var performance = new Performance();
        performance.perform = function (dog) {
            console.log(dog.name);
        };
        performance.do();

        performance.perform = function (cat) {
            console.log(cat.name);
        };
        performance.do();

        performance.perform = function (cat, dog) {
            console.log(cat.name + "  " + dog.name);
        };
        performance.do();
           

使用者不用在乎參數的順序,隻需要提供一定格式的參數名,比如我用cat做參數名,那請給我一個cat的對象,用dog就給我dog對象,如果參數cat dog都有,那請給我兩個對象。

可能你會覺得這種需求還是不怎麼明白,那我舉個大家熟悉的例子

jQuery.ajax({
            data: {},
            success:function(data,state){
        
            },
            error: function (xhr,msg,obj) {

            }
        });
           

這是JQuery的ajax方法,它其中的sucess和error是需要使用者自己定義的函數,但是函數的參數是固定死的,也就是說在error函數中,第一個參數就是xhr對象,第二個參數就是錯誤資訊,使用者不能颠倒順序,或者漏寫前面某個參數而去使用後面的參數。比如,我想直接彈出錯誤資訊:

error: function (msg) {
    alert(msg);
 }
           

可是實際結果是彈出xhr執行個體的toString()結果。

有人可能會說,這是常識吧,所有程式都是這樣執行的啊。

實際上,用過Angular的人都會發現,在使用Angular的過程中,傳參從來不用考慮第一個參數應該是什麼。$http參數放在第一個或者第二個它都是$http執行個體,使用者在factory中定義了一堆service,也隻需要通過參數名就能擷取到,實際上這種體驗要明顯好很多。

然而怎麼去實作呢?第一點就是怎麼擷取參數名稱。其實javascript的每個函數都有toString()方法,我們可以從這個方法入手。

args = fn.substring(fn.indexOf('(') + 1, fn.indexOf(')')).split(',');
           

當我們得到函數toString()後的字元串fn後,就可以通過上面截取字元串的方式獲得參數名集合。

比如,我們拿到的參數裡有名稱為dog的參數,那麼我們就取this["dog"]進而拿到dog對象,用它當參數去調用函數。

下面代碼就是實作文章一開始提到dog還是cat得問題。

var Performance = function () {
            this.dog = { name: 'dog' };
            this.cat = { name: 'cat' };
            this.do = function () {
                var fn = this.perform.toString(),
                    args = fn.substring(fn.indexOf('(') + 1, fn.indexOf(')')).split(',');

                for (var i = 0; i < args.length ; i++) {
                    args[i] = this[args[i].trim()];
                }

                this.perform.apply(this, args);
            }
        };
           

一開始我比較糾結如何将一個數組當參數傳遞給一個方法,後來想起了apply方法,這個方法本質上是為了替換一個函數中this的執行個體的,但是它第二個參數可以接受一個參數數組,這便是我們這裡需要的。

同時,我也檢視了Angular的源碼,确實,和我的思路是一樣的。

繼續閱讀