JS 利用參數個數進行函數重載

分享下《JavaScript忍者祕籍》中的一種函數重載方式

首先說一下函數的length屬性:

全部的函數都有一個常常被忽略的屬性,但卻可讓咱們瞭解函數的聲明,那就是length屬性。和arguments參數的length屬性不一樣的是,它表示函數聲明時所需傳入的形參數量。javascript

function makeNinja(name){};
//makeNinja.length === 1;複製代碼

對一個函數,在參數方面,咱們能夠肯定兩件事情:java

  • 經過其length屬性,能夠知道聲明瞭多少命名參數
  • 經過arguments.length,能夠知道在調用時傳入了多少參數

重載函數的方法:

/* * object爲要綁定方法的對象 * name爲綁定方法所用的屬性名稱 * fn爲要綁定的方法 * */
function addMethod(object, name, fn) {
  //保存原有的函數,由於調用的時候可能不匹配傳入的參數個數
  var old = object[name];
  //建立一個新匿名函數做爲新方法
  object[name] = function () {
    //若是該匿名函數的形參個數和實參個數匹配,就調用該函數
    if (fn.length === arguments.length) {
      return fn.apply(this, arguments)
    //若是傳入的參數不匹配,則調用原有的參數
    } else if (typeof old === 'function') {
      return old.apply(this, arguments);
    }
  }
}複製代碼

用法

var ninja = {};
addMethod(ninja, 'whatever', function () {
  /* do something */
});
addMethod(ninja, 'whatever', function (a) {
  /* do something else */
});
addMethod(ninja, 'whatever', function (a, b) {
  /* yet something else */
});複製代碼

分析

addMethod()第一次調用將建立一個新匿名函數,傳入零個參數進行調用的時候將會調用該fn函數。因爲此時ninja是一個新對象,因此這時候不用擔憂以前建立的方法。數據結構

addMethod()第二次調用的時候,首先將以前的同名函數保存到一個變量old中,而後將新建立的匿名函數做爲方法。新方法首先檢查傳入的函數個數是否爲一,若是是,就調用剛纔傳入的fn函數;若是不是,則從新調用存儲在old上的函數,從新調用該函數時,將會再次檢查參數個數是否爲零,繼而調用參數個數爲零的fn版本的函數。閉包

addMethod()第三次調用的時候,傳入了一個接收兩個參數的fn函數,而後判斷邏輯相同:建立一個匿名函數做爲方法,判斷是否傳入參數的個數爲兩個,若是是則調用兩個參數的fn函數,不然繼續判斷參數個數是否爲一。app

這種方法就像剝洋蔥同樣,每一層都檢查參數個數是否匹配,若是不匹配的話,就進入上一層建立的函數。內部函數是經過閉包訪問到old和fn的。函數

這是一個絕佳的技巧,由於這些函數實際上並無存儲於任何典型的數據結構中,而是在閉包裏做爲引用進行存儲。應該注意的是,在使用這個特定的技巧時,須要注意如下兩點:ui

  • 這個重載只適用於不一樣數量的參數,但並不區分類型、參數名或其餘東西。這些纔是咱們常常想作的事情
  • 這個重載方法會有一些函數調用的開銷
相關文章
相關標籤/搜索