浅谈call(),bind(),apply()
bind,call,apply的作用都是用来改变this指向的。
- 1、首先为什么要改变this的指向呢?
看个示例
var name="lucy";
const obj={
name:"martin",
say:function () {
console.log(this.name);
}
};
obj.say(); //martin,this指向obj对象
setTimeout(obj.say,0); //lucy,this指向window对象
正常调用obj的话,this的指向是没有问题的,但是放到setTimeout中做回调问题就出现了,因为setTimeout因此回到主栈执行时是在全局执行上下文的环境中执行的,这时候this指向自然是window,这显然不符合我们的需求,因此便需要改变this的指向。
- 2、使用call,apply,bind改变this指向的区别
1、三者第一个参数都是this要指向的对象,如果没有这个参数或参数为undefined或null,则默认指向全局window。
2、三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入。
3、bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行 。
-
3、call()
fun.call(thisArg, arg1, arg2, …)
(1)描述
可以让call()中的对象调用当前对象所拥有的function。你可以使用call()来实现继承:写一个方法,然后让另外一个新的对象来继承它(而不是在新对象中再写一次这个方法,详见call函数示例二)。
(2) 参数
thisArg
在 fun函数运行时指定的 this值 。需要注意的是,指定的 this值并不一定是该函数执行时真正的 this值,如果这个函数处于 非严格模式下,则指定为 null和 undefined的 this值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this会指向该原始值的自动包装对象。
arg1, arg2, …
指定的参数列表。
(3)返回值
返回值是你调用的方法的返回值,若该方法没有返回值,则返回undefined。
//call函数示例一
var clothes = "pants";
function Fn() {
console.log(this.clothes);
}
const o = {
clothes: "shirt"
}
Fn(); //此时输出的是pants
Fn.call(o);//此时输出的事shirt,因为call和apply立即执行,所以直接输出
//call函数示例二
function Product(name, price) {
this.name = name;
this.price = price;
if (price < 0) {
throw RangeError(
'Cannot create product ' + this.name + ' with a negative price'
);
}
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
//等同于
function Food(name, price) {
this.name = name;
this.price = price;
if (price < 0) {
throw RangeError(
'Cannot create product ' + this.name + ' with a negative price'
);
}
this.category = 'food';
}
var cheese = new Food('feta', 5);
- 4、apply()函数
fun.apply(obj,[…args])
(1) 参数
apply最多两个参数,
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function(args–>arguments)``
(2) 返回值
返回值是你调用的方法的返回值,若该方法没有返回值,则返回undefined。
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var student = {
firstName:"Bill",
lastName: "Gates"
}
student .fullName.apply(person1, ["Oslo", "Norway"]);//输出Bill Gates,Seatle,USA
通俗一点讲就是:用student去执行Person这个类里面的内容,在Person这个类里面存在this.firstName 等之类的语句,这样就将属性创建到了student对象里面
- 5、什么情况下用apply,什么情况下用cal
在给对象参数的情况下,如果参数的形式是数组的时候,并且在调用对象/函数的时候参数的列表是对应一致的(比如上面Person和Student的参数列表前两位是一致的) 就可以采用 apply 。
如果我的Person的参数列表是这样的(age,name),而Student的参数列表是(name,age,grade),这样就可以用call来实现了,也就是直接指定参数列表对应值的位置(Person.call(this,age,name,grade));
- 6、bind()函数
bind()方法创建一个新的函数(称为绑定函数)。
语法:
fun.bind(thisArg[, arg1[, arg2[, …]]])
参数thisArg表示:当绑定函数被调用时,该参数会作为this的指向。当使用new 操作符调用绑定函数时,该参数无效。
参数arg1, arg2, …表示:当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。
//bind函数示例一
this.name="jack";
var demo={
name:"rose",
getName:function(){return this.name;}
}
console.log(demo.getName());//输出rose 这里的this指向demo
var another=demo.getName;
console.log(another())//输出jack 这里的this指向全局对象
//运用bind方法更改this指向
var another2=another.bind(demo);
console.log(another2());//输出rose 这里this指向了demo对象了