javascript中bind多次綁定和apply,call,bind同時使用的深入理解

之前在看angualr的源碼,看到一個很奇怪的寫法,當時只是大概懂意思,也沒深入研究,最近有時間深入研究了下,然後把自己的分析和理解記錄下來。

1.當bind,call或者apply同時使用

先看一段angualr的源碼:

 function instantiate(Type, locals, serviceName) {
        // Check if Type is annotated and use just the given function at n-1 as parameter
        // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
        var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
        var args = injectionArgs(Type, locals, serviceName);
        // Empty object at position 0 is ignored for invocation with `new`, but required.
        args.unshift(null);
        return new(Function.prototype.bind.apply(ctor, args))();
}

這個代碼的邏輯不需要理解(angualr實例化服務,以後的文章我會解釋),你只需要看後面2行代碼就可以,代碼中ctor是個函數,args是個數組,它把null值放到數組的第一個位置,相當於[null,…],然後return出來一個實例,是不是看起來很迷糊,Function.prototype.bind.apply,又bind,又apply?,啥意思啊,前面有個new肯定知道是實例化對象來的,上一篇文章我說了apply,call,bind的底層實現,不懂的同學可以點擊這裏。這段代碼到底在做什麼呢,其實它是把數組形參(我不知道有多少個形參時候用apply),傳入到ctor函數中,具體的說,就是向構造函數中先傳入參數,然後再實例化出來。下面我來一一分析它的實現原理:
1."Function.prototype.bind"如果你不改寫,這個是所有的函數都有的方法,可以把"Function.prototype.bind"當成一個函數。
2."apply"改變了this的指向。
3."args"數組形參的傳入。
相當於: “函數.apply(函數,形參)”,那麼上面那段代碼就可以改成這樣 “ctor.bind(null,…)”,bind是返回一個新的函數。
來看個理解加深下理解吧:

 function Person(){
     this.name = arguments[0];
     this.age = arguments[1];
     this.sex=arguments[2];
 }
 var p =  Function.prototype.bind.apply(Person,[null,'zhangsan','18','man']); 
 // var p = Person.bind(null,'zhangsan','18','man');
 var p1 = new p();
 console.log(p1.name,p1.age,p1.sex); //zhangsan 18 man

“Function.prototype.bind.apply(Person,[null,‘zhangsan’,‘18’,‘man’]) " 可以改寫成 “Person.bind( null , ‘zhangsan’ , ‘18’ , ‘man’ )”
這就是爲什麼要把null放在數組的最前面。可能有些同學會說這樣寫不也可以?“Function.prototype.apply.bind(Person,[null,‘zhangsan’,‘18’,‘man’]); " 這樣些肯定是不行的,改寫之後” Person.apply( [null , ‘zhangsan’ , ‘18’ , ‘man’] )” ,這樣函數就執行了,你再new就會報錯了。所以"Function.prototype.bind.apply"可以解決實例化構造函數傳入未知形參的問題。

2.當bind多次綁定

先上段測試代碼:

 function foo() {
     console.log(this.value);
 };

 obj = {
     value: 10
 };
 obj1 = {
     value: 100
 };
 obj2 = {
     value: 1000
 };
 var p = foo.bind(obj).bind(obj1).bind(obj2);
 p();//10

爲什麼會是10,bind 綁定之後會返回新的函數,所以代碼我們可以看成 ‘新函數’.bind(obj2),這個’新函數’裏面還有’新函數’,‘新函數’裏面還有’新函數’,知道有這些的話,我們只看最外層的一個就好了,當 p()之後此時最外層的’新函數’的this指向是obj2(1000),然後接着執行裏面的’新函數’,接着this從obj2(1000)指向了obj(100),一直這樣,最後執行到foo.bind(obj),此時this已經指向obj(10)了,所以輸出的結果是10,原理很簡單,多次綁定bind只是一直在改變this的指向,最終還是變回第一次綁定的this。所以bind多次綁定是無效,只有第一次有效果。好了,到這裏就差不多已經說完了(如果有不對之處,歡迎指正,不勝感激!!!),歡樂的時光總是過得特別快,又到時候和大家講拜拜!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章