一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情。
前言
call()、apply()、bind()是面试中常被问到的改变this指向的三剑客,对call()和apply()感兴趣的可以点跳转到相应文章。bind()的使用方式方式和call()、apply()有这很大的区别,在实现上也更加的复杂,下面具体来看看。
bind()干了什么?
如上图,这是mdn中对bind()函数的描述,由此我们可值bind()的特点是
- 调用bind()会返回一个新函数
- 调用bind()得到的函数中this指向bind()的第一个参数,这点和call()及apply()是一样的
实现bind()
由于bind()也可改变this的指向,我们这里可以利用call()来实现改变this指向的效果,代码如下
Function.prototype.myBind = function (context) {
var self = this;
return function () {
return self.call(context);
}
}
dog = {
color:'white'
}
function animal(){
console.log(this.color)
}
var result = animal.myBind(dog)
result()
上面代码的打印结果是white,这说明已经成功的改变了this的指向,要不然打印的应该是undefined。
接下来模拟一下bind()中的参数传递,首先来看一下bind()的参数都可以怎样传递,如下代码
var dog = {
color: 'white'
};
function animal(name, age) {
console.log(this.color);
console.log(name);
console.log(age);
}
var result = animal.bind(dog, '小白');
result('3');
这里的打印结果如下图:
由此我们可以发现使用bind()的时候参数可以在调用bind()的时候传入,也可以在执行bind()的返回函数的时候传入,下面看一下要如何来实现这点。
要实现上面的这点,我们要分为3步
- 首先拿到调用bind()时候传入的参数
- 再拿到执行bind()返回函数时传入的参数
- 把这两步拿到参数都传递给目标函数执行即可
Function.prototype.myBind = function (context) {
var self = this; //这里的this是调用myBind的那个函数
// 获取myBind函数中从第二个参数到最后一个参数
var args = Array.prototype.slice.call(arguments, 1);
return function () {
// 这里的arguments是指bind返回的那个函数传入的参数
var returnFA = Array.prototype.slice.call(arguments);//这句话是把伪数组数组化
return self.call(context, ...args.concat(returnFA));
// return self.apply(context, args.concat(returnFA)); 如果想用apply改变this指向就这样写
}
}
上述代码就实现了两次参数合到一起传递给目标函数,下面实验一下
var dog = {
color: 'white'
};
function animal(name, age) {
console.log(this.color);
console.log(name);
console.log(age);
}
var result = animal.myBind(dog, '小白');
result('3');
结果如下
结果和bind()的结果一样,非常的nice。这里多提一嘴Array.prototype.slice.call(arguments),这里的Array.prototype.slice.call()可以把一个带有length属性的对象转换为数组,如下例子:
var ls = {
0:'小白',
1:3,
length:2
}
//[].slice.call()和Array.prototype.slice.call()一样
var result = Array.prototype.slice.call(ls)
console.log(result)
结果如下:
总结
上述就是模拟bind()功能的一部分,为什么说一部分呢,因为bind()还有个特点,那就是当bind()返回的函数当做构造函数的时候,这时绑定的this失效,并且传入的参数还有用,这点后续再来补充