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
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。