bind( )是什么?

bind()方法会创建一个新的函数,当这个新函数被调用时,bind()的第一个参数将作为他运行时的this,之后的其他参数将在传递的实参前传入作为它的参数.
var obj= {
    value:'value'
}

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

var bindFoo = foo.bind(obj)
bindFoo() // value

从上面的小 demo 中明显能得出两点:bind()方法可以改变 this 的指向,并且他返回的是一个函数(不同于 call 和 apply 返回的是执行结果)

bind 的模拟实现

有了之前实现 call 和 apply 的经验,可以根据这两个明显的特点写一个函数.

  • 改变 this 的指向
  • 返回一个函数
Function.prototype.bind1 = function(context){
    // this 指向的是调用bind1的函数
    var self = this
    // 返回一个函数
    return function (){
        // 调用apply 改变this的指向,并执行这个函数
        return self.apply(context)
    }
}
bind()可以传多个参数,使用 bind 方法返回的函数同样也可以传参数.
var obj = {
    value:"value"
}

function foo (name,age){
    console.log(name)
    console.log(age)
    console.log(this.value)
}
var fBind = foo.bind(obj,'ken',18)
fBind()
// ken
// 18
// value

var fBind1 = foo.bind(obj,'Ann')
fBind1(20)

// Ann
// 20
// value

那么就可以写成这样

Function.prototype.bind2 = function(context){
    var self = this
    // bindArgs是通过 bind 方法传过来的参数,取除了第一个参数以外的全部参数
    var bindArgs = Array.prototype.slice.call(arguments,1)
    return function(){
    // funcArgs 是通过返回的函数传过来的参数
        var funcArgs = Array.prototype.slice.call(arguments)
        return self.apply(context,bindArgs.concat(funcArgs))
    }
}
bind()还有一个特点:bind 返回的函数也可以使用 new 操作符创建对象.这种行为就像把原函数当做构造函数.提供的this值被忽略,同时,调用bind 传递的参数被提供给模拟函数.
也就是说:当 bind 返回的函数作为构造函数使用时,调用 bind 指定的 this 将会失效,但传入的参数依然生效.
var value = "gloablValue"
var obj = {
    value:"value"
}
function foo (name,age){
    this.sex = 'man'
    console.log(name)
    console.log(age)
    console.log(this.value)
}
foo.prototype.habit = 'play games'

var fooFunc = foo.bind(obj,"Ken",18)
// value
// Ken
// 18
var fooObj = new fooFunc()
console.log(fooObj.value)  // undefined
console.log(fooObj.sex)  // man
console.log(fooObj.habit)  // play games

使用返回的函数创建了一个新的实例,this指向了实例

Function.prototype.bind3 = function(context){
    var self = this
    var bindArgs = Array.prototype.slice.call(arguments,1)
    var f = function(){
        var funcArgs = Array.prototype.slice.call(arguments)
        // 当f作为构造函数时:this指向的是实例,此时结果为true.将绑定函数的this(上面的self) 指向该实例,可以让实例获得来自绑定函数的值
        // 当f作为普通函数时:this 指向的是 window,此时结果为 false.将版抵挡函数的 this 指向传进来的 context
        return self.apply(this instance f ? this : context, bindArgs.concat(funcArgs))
    }
    // 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继续继承绑定函数的原型中的值.
    f.prototype = this.proptotype
    return f
}

还有一个小问题:如果我们修改了 f 的 prototype那么绑定函数的 prototype 也会改变.可以添加一个函数作为中间转换

Function.prototype._bind = function(context){
    // 如果调用 bind 的不是函数,直接报错
    if(typeof this !== 'function'){
        thorw newError("Function.prototype.bind - what is trying to be bound is not callable")
    }
    var self = this
    var bindArgs = Array.prototype.slice.call(arguments,1)
    var fTmp = function(){}
    var f = function(){
        var funcArgs = Array.prototype.slice.call(arguments)
        return self.apply(this instanceof f ? this : context , bindArgs.concat(funcArgs))
    }
    fTmp.prototype = this.prototype
    f.prototype = new fTmp()
    return f
}

参考文章

https://github.com/mqyqingfen...


好好学习
7 声望2 粉丝

文章是自己在学习或踩到坑的过程中查找资料的总结,以便后期自己复习使用