bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
从MDN对于bind的描述来看:
- 返回值是一个函数,而不是执行结果
- this值会指向第一个参数
- 其余参数会作为新函数的参数
看个例子:
function test(name, age) {
console.log(this.name);
this.name = name;
this.age = age;
console.log(this.name, this.age);
}
var obj = {
name: 'Willem'
};
var bindFn = test.bind(obj, 'Wei');
bindFn(18);
// Willem
// Wei, 18
从上面的代码就可以看出来,bind函数执行之后,bindFn的this值指向了obj,并且在bind的时候传入的参数和在执行bindFn时传入的参数都成功的传入了test函数。
那代码就呼之欲出了啊。
Function.prototype.wbind = function() {
var context = [].shift.call(arguments);
var args = [].slice.call(arguments);
var self = this;
return function() {
var innerArgs = [].slice.call(arguments);
self.apply(context, args.concat(innerArgs));
}
}
既然bind返回的是一个函数,那我有一个大胆的想法,如果我把这个返回的函数作为一个构造函数会怎样呢?改造一下上面的那个例子:
function test(name, age) {
console.log(this.name);
this.name = name;
this.age = age;
console.log(this.name, this.age);
}
test.prototype.sayHi = function() {
console.log('Hi, ' + this.name);
}
var obj = {
name: 'Willem'
};
var bindFn = test.bind(obj, 'Wei');
var instance = new bindFn(18);
// undefined
// Wei,18
instance.sayHi(); // Hi, Wei
console.log(obj.name); // Willem
咦,obj对象里面明明是有name属性的啊,为啥第一次输出的是undfined呢?明明传入了name属性为"Wei",为啥obj.name还是"Willem"呢?
其实是因为this并没有指向obj了,而是指向了instance
。总结一下,将返回的函数作为普通函数使用时,函数的this指向bind执行时传入的第一个参数;将返回的函数作为构造函数使用时,函数的this指向实例,并且该实例将会继承原函数原型上的属性和方法。
这时候,我们再来改一改wbind函数
:
Function.prototype.wbind = function() {
var context = [].shift.call(arguments);
var args = [].slice.call(arguments);
var self = this;
var fBound = function() {
var innerArgs = [].slice.call(arguments);
// 做构造函数时,this指向实例
self.apply(this instanceof fBound ? this : context, args.concat(innerArgs));
}
// 实例需要继承原函数原型上的方法和属性
// 使用fNOP中转一次是因为直接将this.prototype赋值到fNOP.prototype时
// 当修改fNOP的prototype时,this.prototype也会被修改
var fNOP = function() {}
if (this.prototype) {
fNOP.prototype = this.prototype;
}
// fBound.prototype = { __proto__: { this.prototype } }
// 相当于是中间多了一个__proto__,因为原型链的缘故,所以多一层__proto__没有什么影响
fBound.prototype = new fNOP();
return fBound;
}
相关:
模拟实现js中的new操作符
简单说说原型和原型链
使用ts模拟实现js中的一些函数和属性
以上,就是bind的相关内容。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。