js中的改变this指向的apply、call和bind的区别和使用
日期:2019-01-07
来源:程序思维浏览:2769次
在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢。
在说区别之前还是先总结一下三者的相似之处:
1、都是用来改变函数的this对象的指向的。
2、第一个参数都是this要指向的对象。
3、都可以利用后续参数传参。
代码案例展示:
call示例展示:
var obj1={
name:"李四",
person:function (args) {
console.log(this.name,args);
}
};
var obj2={
name:"张三",
person:function () {
console.log(this.name);
}
};
obj1.person.call(obj2, "传参");
apply示例展示:
var obj1={
name:"李四",
person:function () {
console.log(Array.prototype.slice.apply(arguments));//arguments转真实数组
//console.log(this.name,args);
},
person2:function (...args) {//es6接收参数
console.log(args);
//console.log(this.name,args);
}
};
var obj2={
name:"张三",
person:function () {
console.log(this.name);
}
};
obj1.person.apply(obj2, ['参数1','参数2']);
obj1.person2.apply(obj2, ['参数1','参数2']);
bind示例展示:
var obj1={
name:"李四",
person:function (args) {
console.log(this.name,args);
}
};
var obj2={
name:"张三",
person:function () {
console.log(this.name);
}
};
//第一种调用方法
var fnPerson=obj1.person.bind(obj2, "传参");
fnPerson();
//第二种调用方法
obj1.person.bind(obj2, "传参")();
好了例子很简单但是基本的使用方法跟场景都涉及到了。
call跟apply的用法几乎一样,唯一的不同就是传递的参数不同,call只能一个参数一个参数的传入。
apply则只支持传入一个数组,哪怕是一个参数也要是数组形式。最终调用函数时候这个数组会拆成一个个参数分别传入。
至于bind方法,他是直接改变这个函数的this指向并且返回一个新的函数,之后再次调用这个函数的时候this都是指向bind绑定的第一个参数。bind传参方式跟call方法一致。
由于apply函数传参的特殊性,我们又衍生出了一个黑魔法。
如果一个数组我们已知里面全都是数字,想要知道最大的那个数,由于Array没有max方法,Math对象上有
我们可以根据apply传递参数的特性将这个数组当成参数传入
最终Math.max函数调用的时候会将apply的数组里面的参数一个一个传入,恰好符合Math.max的参数传递方式
这样变相的实现了数组的max方法。min方法也同理
const arr = [1,2,3,4,5,6]
const max = Math.max.apply(null, arr)
console.log(max) // 6
这里bind函数也有一个小技巧
如果你想将某个函数绑定新的`this`指向并且固定先传入几个变量可以在绑定的时候就传入,之后调用新函数传入的参数都会排在之后
const obj = {}
function test(...args) {console.log(args)}
const newFn = test.bind(obj, '静态参数1', '静态参数2')
newFn('动态参数3', '动态参数4')
总结:
在说区别之前还是先总结一下三者的相似之处:
1、都是用来改变函数的this对象的指向的。
2、第一个参数都是this要指向的对象。
3、都可以利用后续参数传参。
代码案例展示:
call示例展示:
var obj1={
name:"李四",
person:function (args) {
console.log(this.name,args);
}
};
var obj2={
name:"张三",
person:function () {
console.log(this.name);
}
};
obj1.person.call(obj2, "传参");
apply示例展示:
var obj1={
name:"李四",
person:function () {
console.log(Array.prototype.slice.apply(arguments));//arguments转真实数组
//console.log(this.name,args);
},
person2:function (...args) {//es6接收参数
console.log(args);
//console.log(this.name,args);
}
};
var obj2={
name:"张三",
person:function () {
console.log(this.name);
}
};
obj1.person.apply(obj2, ['参数1','参数2']);
obj1.person2.apply(obj2, ['参数1','参数2']);
bind示例展示:
var obj1={
name:"李四",
person:function (args) {
console.log(this.name,args);
}
};
var obj2={
name:"张三",
person:function () {
console.log(this.name);
}
};
//第一种调用方法
var fnPerson=obj1.person.bind(obj2, "传参");
fnPerson();
//第二种调用方法
obj1.person.bind(obj2, "传参")();
好了例子很简单但是基本的使用方法跟场景都涉及到了。
call跟apply的用法几乎一样,唯一的不同就是传递的参数不同,call只能一个参数一个参数的传入。
apply则只支持传入一个数组,哪怕是一个参数也要是数组形式。最终调用函数时候这个数组会拆成一个个参数分别传入。
至于bind方法,他是直接改变这个函数的this指向并且返回一个新的函数,之后再次调用这个函数的时候this都是指向bind绑定的第一个参数。bind传参方式跟call方法一致。
由于apply函数传参的特殊性,我们又衍生出了一个黑魔法。
如果一个数组我们已知里面全都是数字,想要知道最大的那个数,由于Array没有max方法,Math对象上有
我们可以根据apply传递参数的特性将这个数组当成参数传入
最终Math.max函数调用的时候会将apply的数组里面的参数一个一个传入,恰好符合Math.max的参数传递方式
这样变相的实现了数组的max方法。min方法也同理
const arr = [1,2,3,4,5,6]
const max = Math.max.apply(null, arr)
console.log(max) // 6
这里bind函数也有一个小技巧
如果你想将某个函数绑定新的`this`指向并且固定先传入几个变量可以在绑定的时候就传入,之后调用新函数传入的参数都会排在之后
const obj = {}
function test(...args) {console.log(args)}
const newFn = test.bind(obj, '静态参数1', '静态参数2')
newFn('动态参数3', '动态参数4')
总结:
- 当我们使用一个函数需要改变this指向的时候才会用到call、apply、bind
- 如果你要传递的参数不多,则可以使用fn.call(thisObj, arg1, arg2 ...)
- 如果你要传递的参数很多,则可以用数组将参数整理好调用fn.apply(thisObj, [arg1, arg2 ...])
- 如果你想生成一个新的函数长期绑定某个函数给某个对象使用,则可以使用const newFn = fn.bind(thisObj); newFn(arg1, arg2...)
精品好课