全部的函數都有一個常常被忽略的屬性,但卻可讓咱們瞭解函數的聲明,那就是length屬性。和arguments參數的length屬性不一樣的是,它表示函數聲明時所需傳入的形參數量。javascript
function makeNinja(name){};
//makeNinja.length === 1;複製代碼
對一個函數,在參數方面,咱們能夠肯定兩件事情:java
/* * 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