【JavaScript】JS 中實現方法重載


方法重載是根據形參的數量、類型不同而調用相應的同名方法。

JavaScript 方法本身是不存在方法重載的,后一個方法會覆蓋前面的同名方法:

function fun() {
    return 1;
}
function fun(param) {
    return 2;
}
fun(); //2
fun(0); //2

JavaScript 中實現函數重載,主要有兩種途徑(沒有考慮到參數的類型):

  • 利用arguments類數組來判斷實參個數
  • 利用閉包保存之前注冊進來的同名函數

通過arguments實現

arguments.length可以獲得實參的數量,函數名.length 可以獲取形參的數量。

這里我們可以實現通過實參的數量不同來實現不同的處理。

function fun() {
    if(arguments.length == 0) {
        return 1;
    } else if(arguments.length == 1) {
        return 2;
    }
}
fun();  //1
fun(0); //2

閉包實現方法重載

閉包是指有權訪問另一個函數作用域變量的函數,創建閉包的通常方式,是在一個函數內部創建另一個函數。

想深入了解閉包可以看這篇文章,講得很好。

先來個網上很容易搜到的閉包實現方法重載的例子

function addMethod (object, name, fn) {
  // 把前一次添加的方法存在一個臨時變量old中
  var old = object[name];

  // 重寫object[name]方法
  object[name] = function () {
    if (fn.length === arguments.length) {
      // 若是調用object[name]方法時,若是實參和形參個數一致,則直接調用
      return fn.apply(this, arguments);
    } else if (typeof old === 'function') {
      // 若是實參形參不一致,判斷old是不是函數,若是,就調用old
      return old.apply(this, arguments);
    }
  };
}

var people = {
  values: ['Dean Edwards', 'Sam Stephenson', 'Alex Russell', 'Dean Tom']
};

//find all values
addMethod(people, 'find', function() {
  return this.values;
});

//find value by fisrtName
addMethod(people, 'find', function(firstName) {
  return this.values.filter((value) => {
    return value.indexOf(firstName) !== -1 ? true : false;
  });
});

//find value by firstName and lastName
addMethod(people, 'find', function(firstName, lastName) {
  return this.values.filter((value) => {
    var fullName = `${firstName} ${lastName}`;
    return value.indexOf(fullName) !== -1 ? true : false;
  });
});

console.log(people.find());      // ["Dean Edwards", "Sam Stephenson", "Alex Russell", "Dean Tom"]
console.log(people.find('Dean'));       // ["Dean Edwards", "Dean Tom"]
console.log(people.find('Dean', 'Edwards'));    // ["Dean Edwards"]

現在來深入解析下這個例子,方便理解閉包如何實現方法重載。

可以看到 addMethod 方法被調用了三次,每一次調用都會產生一個新的匿名函數,並且這個新的匿名函數通過閉包包含着一個 old 變量和fn函數。

addMethod方法在每次執行時,都會生成一個 addMethod 的活動變量和執行環境,執行完畢以后完后都只是銷毀了執行環境,但活動對象由於被閉包函數所引用,仍然保留。old 中包含之前舊的方法。這樣就像洋蔥一樣一層一層。通過閉包訪問oldfn來實現函數的重載。

當第一次調用 addMethod時,people["find"]沒有定義,所以 old被賦值為 undefined(不妨記為old1),然后開始重寫people["find"]不妨記為find1,以便理解。然后addMethod執行完畢,由於oldfn(記為fn1)被 people["find"]方法引用,所以活動對象仍然保留。

當第二次調用 addMethod時,people["find"]是find1,所以 old被賦值為 find1(需要注意的是這個old是一個新的局部變量,不妨記為old2),然后開始重寫people["find"]不妨記為find2。然后addMethod執行完畢,由於oldfn(記為fn2)被 `people["find"]方法引用,所以活動對象仍然保留。

當第三次調用 addMethod時,people["find"]是find2,所以 old被賦值為 find2 (記為old3),然后開始重寫people["find"]不妨記為find3。然后addMethod執行完畢,由於oldfn(記為fn3)被 `people["find"]方法引用,所以活動對象仍然保留。

當我們調用 people.find()時,由於此時的 people.find是 find3,實參個數為0,fn3的形參個數為2,兩者個數不等,所以 執行old.apply(this, arguments); 。這個 old 是 old3,值是find2。

find2 中 fn2 的形參個數為 1,也不同,所以執行old.apply(this, arguments); 這個 old 是 old2,值是find1。

find1 中 fn1 的形參個數為 0,實參和形參個數相同,所以執行fn.apply(this, arguments);

相信你如果對閉包有所了解,還是很容易理解上面的每一步的。


免責聲明!

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



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