描述
bind() 函数会创建一个新的绑定函数(bound function,BF)。绑定函数是一个 exotic function object(怪异函数对象,ECMAScript 2015 中的术语),它包装了原函数对象。调用绑定函数通常会导致执行包装函数。
绑定函数具有以下内部属性:
- [[BoundTargetFunction]] - 包装的函数对象
- [[BoundThis]] - 在调用包装函数时始终作为 this 值传递的值。
- [[BoundArguments]] - 列表,在对包装函数做任何调用都会优先用列表元素填充参数列表。
- [[Call]] - 执行与此对象关联的代码。通过函数调用表达式调用。内部方法的参数是一个this值和一个包含通过调用表达式传递给函数的参数的列表。
当调用绑定函数时,它调用 [[BoundTargetFunction]] 上的内部方法 [[Call]],就像这样 Call(boundThis, args)。其中,boundThis 是 [[BoundThis]],args 是 [[BoundArguments]] 加上通过函数调用传入的参数列表。
绑定函数也可以使用 new
运算符构造,它会表现为目标函数已经被构建完毕了似的。提供的 this
值会被忽略,但前置参数仍会提供给模拟函数。
实现
// fn.bind(content) bind 返回函数
Function.prototype.myBind = function (context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const _this = this
const args = [...arguments].slice(1)
// 返回一个函数
return function F() {
// 因为返回了一个函数,我们可以 new F(),所以需要判断
if (this instanceof F) {
// 此时的this 是new 出来的obj,跟context 没有关系, 参照下面的 demo
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}
Function.prototype.bind = function(thisObj) {
// 判断调用 bind 的方法是不是一个函数
if(typeof this !== 'function') {
throw new TypeError('只能对函数使用 bind 方法')
}
// 保存当前函数的指针
const self = this;
// 拿到除第一个参数以外的其他参数列表
const args = [].slice.call(arguments,1)
function Bound() {
// 如果 this instanceof Bound,说明是通过 new 关键字调用
// 这时就将 this 直接绑定到 self,而忽略 thisObj,在 self 内部会对 this 添加属性和方法
return self.apply(this instanceof Bound ? this : thisObj,args.concat([].slice.apply(arguments)))
}
// 实现继承
if(this.prototype){
Bound.prototype = Object.create(this.prototype)
}
return Bound
}
// call apply 判断是否为对象 bind判断对否为方法
demo
let value = 2;
let foo = {
value: 1
};
function bar(name, age) {
this.habit = 'shopping';
console.log(this.value);
console.log(name);
console.log(age);
}
bar.prototype.friend = 'kevin';
let bindFoo = bar.bind(foo, 'Jack');
let obj = new bindFoo(20);
// undefined
// Jack
// 20
obj.habit;
// shopping
obj.friend;
// kevin
// 上面例子中,运行结果 `this.value` 输出为 `undefined` ,这不是全局 `value` 也不是 `foo` 对象中的 `value` ,
// 这说明 `bind` 的 `this` 对象失效了,`new` 的实现中生成一个新的对象,这个时候的 `this` 指向的是 `obj` 。