简介
说明
本文介绍JavaScript如何改变this的指向。
ES5中this的指向以及ES6中箭头函数的指向
方法简介
一共有如下5种方法改变this的指向。
- this替换
- 箭头函数
- call
- apply
- bind
为什么要改变指向
需求:写一个定时任务,一秒钟之后执行,执行时调用另一个函数。
问:你觉得下方的程序能否执行?
let name = "Hello";
let obj = {
name: "Tony",
func1: function() {
console.log(this.name);
},
func2: function() {
setTimeout(function() {
this.func1()
}, 1000);
}
};
obj.func2();
结果
Uncaught TypeError: this.func1 is not a function
原因
调用obj.func2,在setTimeout中调用this.func1,但setTimeout里边的函数在1秒钟后是由window对象调用的,所以this指向window,但window中没有func1函数,所以会报错。
法1:this替换
func2函数中,this指向对象obj,把this指向赋值给_this,在setTimeout中使用_this来访问func1。
let name = "Hello";
let obj = {
name: "Tony",
func1: function() {
console.log(this.name); // Tony
},
func2: function() {
let _this = this;
setTimeout(function() {
console.log(_this); // {name: 'Tony', func1: ƒ, func2: ƒ} 即:obj对象
_this.func1()
}, 1000);
}
};
obj.func2();
结果
{name: 'Tony', func1: ƒ, func2: ƒ}
Tony
法2:箭头函数
ES6的新特性:箭头函数。
let name = "Hello";
let obj = {
name: "Tony",
func1: function() {
console.log(this.name); // Tony
},
func2: function() {
setTimeout(() => {
console.log(this); // {name: 'Tony', func1: ƒ, func2: ƒ} 即:obj对象
this.func1()
}, 1000);
}
};
obj.func2();
结果
{name: 'Tony', func1: ƒ, func2: ƒ}
Tony
法3:call
说明
call执行一个函数:函数名.call(作用域对象),将函数放到特定的作用域对象中执行。下面这个例子中通过call将setTimeout函数的作用域对象从window改成了obj。
用法
function.call(thisArg, 参数1, 参数2, 参数3...)
function: 要改变this指向的原函数
thisArg: 要改变到的this指向的目标对象
示例
let name = "Hello";
let obj = {
name: "Tony",
func1: function() {
console.log(this.name); // Tony
},
func2: function() {
setTimeout(function() {
console.log(this); // {name: 'Tony', func1: ƒ, func2: ƒ} 即:obj对象
this.func1()
}.call(obj), 1000);
}
};
obj.func2();
结果
{name: 'Tony', func1: ƒ, func2: ƒ}
Tony
法4:apply
说明
apply执行一个函数,函数名.apply(作用域对象)。
用法
function.apply(thisArg, [参数1, 参数2, 参数3...])
function: 要改变this指向的原函数
thisArg: 要改变到的this指向的目标对象
如果打印形参,结果并不是一个数组,而是数组里面的值,并且元素与形参一一对应
示例
let name = "Hello";
let obj = {
name: "Tony",
func1: function() {
console.log(this.name); // Tony
},
func2: function() {
setTimeout(function() {
console.log(this); // {name: 'Tony', func1: ƒ, func2: ƒ} 即:obj对象
this.func1()
}.apply(obj), 1000);
}
};
obj.func2();
结果
{name: 'Tony', func1: ƒ, func2: ƒ}
Tony
法5:bind
语法
funtion.bind(thisArg, 参数1, 参数2, 参数3...)
thisArg: 要改变到的this指向的目标对象 该方法并不会调用函数,仅仅改变了this指向。
示例
let name = "Hello";
let obj = {
name: "Tony",
func1: function() {
console.log(this.name); // Tony
},
func2: function() {
setTimeout(function() {
console.log(this); // {name: 'Tony', func1: ƒ, func2: ƒ} 即:obj对象
this.func1()
}.bind(obj), 1000);
}
};
obj.func2();
call,apply,bind的区别
相同点
都可以改变函数内部的this指向
不同点
项 | call | apply | bind |
是否调用函数 | 立即执行函数 | 立即执行函数 | 不立即执行函数。 返回新函数,便于稍后调用 |
传参 | 可以。 传数组。 一次性传入参数。 | 可以。 传参数列表。 一次性传入参数。 | 可以。 可以多次传入参数。 |
使用场景 | 继承 | 经常跟数组有关系。比如借助数学对象实现数组最大值最小值 | 改变定时器内部的this指向 |