美麗的閉包,在js中實現函數重載

引言

最近在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方法,在不傳參,傳了一個參數,與傳了兩個參數時,函數執行的具體過程,設計

  • person.show(10, 20)
1
2
bear鮑的小小熊---->30

可見,傳入兩個參數的時候,只打印了一個1,一個2,就將對應的執行函數執行了.其實這個時候person.show函數的做用域內 fn爲下面這個函數code

function (a, b) {
        console.log(this.userName + '---->' + (a + b))
    }
  • person.show('bkl')
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)
    }
  • person.show()
1
3
1
3
1
2
bear鮑的小小熊---->show1

上面的也是同理,根據這個輸出結果,不難看出,當沒有傳遞參數時,經過閉包的old變量,咱們能夠一路向上找到這個方法.

function () {
        console.log(this.userName + '---->' + 'show1')
    }

結語

就這樣,咱們經過閉包中的old變量,將對不傳參數,傳了一個參數和傳了兩個參數進行區別處理的方法給串聯了起來.實現了js的重載.再次感嘆一下,這個方法真的很巧妙.真是漂亮又充滿魅力的代碼

若是以爲還能夠,請點贊鼓勵一下,謝謝!

相關文章
相關標籤/搜索