介绍
在js中,每个函数的原型都指向Function.prototype对象(js基于原型链的继承)。因此,每个函数都会有apply,call,和bind方法,这些方法继承于Function。
它们的作用是一样的,都是用来改变函数中this的指向。
使用方法
apply的用法可以表示如下:
A.apply(B, [x, y, z]);
此方法可以改变函数A的this指向,使之指向函数B。第二个参数传的是一个函数参数列表的数组形式。
call的用法和apply差不多,就只有传参方式不一样。类似于这样 :
A.apply(B, x, y, z)
可以把多个参数分开来传,而不是像apply一样,需要把所有参数放到一个数组里边传进来。
bind的传参方式和call一样,只不过它的不同之处是,apply和call方法调用之后会立即执行,而bind方法调用之后会返回一个新的函数,它并不会立即执行,需要我们手动执行。
举例
var name = "佚名";
var age = 20;
//global.name
//global.age
var p1 = {
name: "张三",
age: 12,
func: function(){
console.log(`姓名:${this.name},年龄:${this.age}`)
}
}
var p2 = {
name: "李四",
age: 15
}
p1.func(); //姓名:张三,年龄:12
p1.func.call(); //姓名:佚名,年龄:20
p1.func.apply(p2); //姓名:李四,年龄:15
p1.func.bind(p2)(); //姓名:李四,年龄:15
- 当直接调用p1.func方法时,this指向的是当前p1这个对象,因此name和age都是它本身对象的属性值。
- 当使用call方法,传入的第一个参数为空时,在浏览器环境下,this指向window;在node环境下,this指向global。读者可自行把name和age改为global.name和global.age验证一下。
- 使用apply方法时,把p2传进去,相当于把函数的this指向p2对象,因此,此时打印出来的属性都是p2对象的属性
- 使用bind方法时,会生成一个新的函数对象,因此需要手动执行一下这个函数(即在函数末尾加个括号执行)。
总结
例子讲完,call,apply和bind的区别就已经很清楚了。它们就是为了改变this的上下文而存在。因此,有时候你会看到这样的用法。为了不改变this的指向,通常会在函数后边加上bind(this),如下
function f(){}.bind(this)
这样的话,就不会出现莫名其妙的this指向问题了。明明我想在函数里边调用此函数所属对象的某个属性时,为什么用this却访问不到呢。(写js的新手肯定会遇到过这种问题)
其实,从es6开始,已经支持箭头函数了,我建议大家用箭头函数,就不会出现this指向的问题了。
另外,使用call,apply还可以实现函数的继承。在es6的class没有出现之前,就需要借助它们来实现继承关系。