最近在js的學習中,看到了函數重載的問題,一開始,只看到了實現代碼,看着代碼左思右想了半個小時,總算是理清了其實現的原理,也爲其實現的巧妙感到讚歎,也是在本身搞懂原理以後,去網絡上搜索了下,才知道,這個實現方法是jQuery做者John Resig在《JavaScript忍者祕籍》中對函數重載的實現,設計十分的巧妙,寫下此文,給你們作一個分享bash
重載,簡單說,就是函數或者方法有相同的名稱,可是參數列表不相同的情形,這樣的同名不一樣參數的函數或者方法之間,互相稱之爲重載函數或者方法。網絡
function addMethod (obj, name, fn) { var old = obj[name]; obj[name] = function () { if (fn.length === arguments.length) { return fn.apply(this, arguments) } else if (typeof old === 'function') { return old.apply(this, arguments) } } } var person = {userName: 'bear鮑的小小熊'} addMethod(person, 'show', function () { console.log(this.userName + '---->' + 'show1') }) addMethod(person, 'show', function (str) { console.log(this.userName + '---->' + str) }) addMethod(person, 'show', function (a, b) { console.log(this.userName + '---->' + (a + b)) }) person.show() person.show('bkl') person.show(10, 20)
輸出的結果閉包
//bear鮑的小小熊---->show1 //bear鮑的小小熊---->bkl //bear鮑的小小熊---->30
咱們給一個對象添加了一個show方法,這個show方法,每次傳入的參數不同,它進行的處理也是不同的app
爲了後文更好理解,這裏先對fn.length這個你們可能陌生的屬性作個解釋,先看下面的代碼函數
function fn(a,b,c) {} fn.length // 3 function fn(a,b,c,d) {} fn.length // 4
fn.legnth,是函數fn在定義時,形參的個數.好了,讓咱們繼續往下講吧學習
這個addMethod函數,簡單的來講,就是給一個對象添加一個指定name的方法fn(後文中爲了方便你們理解,咱們就以這個例子中的show來指代這個name吧),他利用了閉包,經過變量old,將每次傳進來的fn給保存起來,咱們每次調用這個show方法,根據傳入的參數的不一樣,咱們的代碼可能屢次經過old來找到以前傳入的fn函數this
下面咱們來對這個方法進行解析爲了看的更加直觀,咱們對以前的addMethod的函數作一點小小的改造,其實就是加入了一個console.log(),能夠方便咱們理解,函數的執行過程spa
function addMethod (obj, name, fn) { var old = obj[name]; obj[name] = function () { console.log(1) //打印1 if(fn.length === arguments.length){ console.log(2) // 打印2 return fn.apply(this,arguments); }else if(typeof old === 'function'){ console.log(3) // 打印3 return old.apply(this,arguments); } } } addMethod(person, 'show', function () { console.log(this.userName + '---->' + 'show1') }) addMethod(person, 'show', function (str) { console.log(this.userName + '---->' + str) }) addMethod(person, 'show', function (a, b) { console.log(this.userName + '---->' + (a + b)) })
下面,咱們看一下person.show方法,在不傳參,傳了一個參數,與傳了兩個參數時,函數執行的具體過程,設計
1 2 bear鮑的小小熊---->30
可見,傳入兩個參數的時候,只打印了一個1,一個2,就將對應的執行函數執行了.其實這個時候person.show函數的做用域內 fn爲下面這個函數code
function (a, b) { console.log(this.userName + '---->' + (a + b)) }
1 3 1 2 bear鮑的小小熊---->bkl
傳入一個參數的時候執行結果爲 1 --> 3 --> 1 --> 2 --> 處理後的結果 在這個過程當中因爲執行person.show方法時,fn.length === 2,而咱們傳入的參數爲1個,那麼函數會執行到
return old.apply(this,arguments);
這個時候的old是什麼呢?這個時候的old實際上是在下面這個函數執行以前的person.show方法
addMethod(person, 'show', function (a, b) { console.log(this.userName + '---->' + (a + b)) })
執行以後person.show函數做用域內的fn函數也就是下面這個方法
function (str) { console.log(this.userName + '---->' + str) }
1 3 1 3 1 2 bear鮑的小小熊---->show1
上面的也是同理,根據這個輸出結果,不難看出,當沒有傳遞參數時,經過閉包的old變量,咱們能夠一路向上找到這個方法.
function () { console.log(this.userName + '---->' + 'show1') }
就這樣,咱們經過閉包中的old變量,將對不傳參數,傳了一個參數和傳了兩個參數進行區別處理的方法給串聯了起來.實現了js的重載.再次感嘆一下,這個方法真的很巧妙.真是漂亮又充滿魅力的代碼
若是以爲還能夠,請點贊鼓勵一下,謝謝!