JavaScirpt 的 bind 函式究竟做了哪些事

catchonme發表於2019-01-18

文章原地址


ES5 實現 bind 函式如下

Function.prototype.bind = function(that){
        var self = this,
            args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
            F = function(){};

        var bound = function(){
            var context = that, length = arguments.length;
            if (this instanceof bound){
                F.prototype = self.prototype;
                context = new F;
            }
            var result = (!args && !length)
                ? self.call(context)
                : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
            return context == that ? result : context;
        };
        return bound;
    }
複製程式碼

測試1

var bar = function() {
        console.log(this.x)
    }
var foo = {
  x: 3
}

var func = bar.bind(foo);
func(); // 3
複製程式碼

bar 函式繫結foo 中的x 值,然後輸出3

bind 函式中最主要的是bound 函式,bound 函式做了哪些事呢?

首先context 儲存傳入的thatcontext 中,判斷this instanceof bound ,那什麼時候this instanceof bound == true 呢?在測試1中的案例中,this instanceof boundfalse ,列印此時的this 輸出Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} ,發現是window 物件,因為foo 本身就是在window 物件中。

所以此時直接執行self.call(context) ,返回執行的結果3 ,就是我們測試1中的結果。

那什麼時候this instanceof bound == true 呢,而且此時還需要使用空函式F 來獲取主函式的prototype

答案是例項化,什麼時候例項化呢?

測試2

var bar = function() {
    console.log(this.x)
}
bar.prototype.name = function(){
  this.name = `name`;
}
var foo = {
  x: 3
}

var func = bar.bind(foo);
var newFunc = new func; // undefined
newFunc.name(); // name
複製程式碼

bar.bind(foo) 進行例項化,此時因為進行了new 操作,new 操作做了什麼呢,參考new操作符裡面到底發生了什麼?所以此時的this 為新生成的bound {} 物件,constructorbound 函式,所以此時this instanceof bound == true

那為什麼bar.bind(foo)foo 物件傳遞的時候,沒有輸出3 而是undefined 呢?也是因為new 操作,當前的上下文已經是新生成的newFunc 函式了。而且當this instanceof bound == true 時,會把barprototype 賦給F 函式,而bound 函式返回的是new F ,所以這時barprototype 也賦給newFunc 了。

我們看看ES6的操作,結果和上述例子是一樣的。

var bar = function() {
    console.log(this.x)
}
bar.prototype.name = function(){
    console.log(`name`)
}
var foo = {
    x: 3
}
var func = bar.bind(foo);
func(); // 3
// 例項化
var newFunc = new func; // undefined
    newFunc.name(); // name
複製程式碼

總結:

所以bind 函式總共做了哪幾件事呢?

  • 沒有例項化時,將傳入物件的引數引用到當前函式,執行當前函式,返回結果
  • 例項化時,使用new 操作生成新函式,原函式的prototype 賦給新函式,執行新函式,並返回新函式

相關文章