this 是什么?
this
是 JavaScript 中的一个关键字,MDN 这样解释:this
是指当前执行代码的环境对象。
根据语义,我这里把它理解为 ”引用指针“ 。
this 的用法?
在大树云设备服务器中,大量使用了this
关键字,因为它可以很方便的让我们在不同的地方操作同一个实例。
举个最简单,最常见的例子:
function App(name){
this.name = name
}
let btc = new App('大树云')
console.log(btc.name) // 大树云
例子中,function app()
是构造函数,btc
是实例化对象。this
就指向 btc
,这是最常见的 this
的用法。
是不是感觉很简单,如果实际开发中的代码都这么简单,那 this
的指向也就简单明了了 ……
来点稍微复杂的看看:
setTimeOut 中的 this
var a = '我是全局变量'
function Foo(){
this.a = '我是局部变量';
this.say = function(){
setTimeout(function() {
console.log(this.a)
console.log(this)
}, 2000);
}
}
var foo = new Foo()
// 浏览器中:
foo.say() // 我是全局变量, Window{}
// Node 环境:
foo.say() // undefined, TimeOut{}
上面的代码,在浏览器与 Node 中执行的结果是不一样的 ,如上面代码所示,出现这样的结果的原因是:
在浏览器中,setTimeout
中的 this
指向的是 Window
对象,这是由于 setTimeout
调用的代码运行在与所在的函数完全分离的执行环境上,所以指向了 Window
。
所以,浏览器与 Node 环境同样的代码执行结果可能会有偏差,本文以 Node 环境为主。
想要得到期望的结果,可以修改代码:
var a = '我是全局变量'
function Foo(){
this.a = '我是局部变量';
this.say = function(){
let that = this
setTimeout(function() {
console.log(that.a)
console.log(that)
}, 2000);
}
}
var foo = new Foo()
foo.say() // '我是局部变量', Foo { a: '我是局部变量', say: [Function] }
上面的代码
let that = this //将 this 存为一个变量,此时的 this 指向 Foo
也可以修改如下:
箭头函数中的 this
var a = '我是全局变量'
function Foo(){
this.a = '我是局部变量';
this.say = function(){
let that = this
setTimeout(() => {
console.log(that.a)
console.log(that)
}, 2000);
}
}
var foo = new Foo()
foo.say() // '我是局部变量', Foo { a: '我是局部变量', say: [Function] }
上面的代码;将回调函数换成了箭头函数,这是因为箭头函数中的 this
总是指向外层调用者,也就是 Foo
再或者:
如何改变 this 的指向
var a = '我是全局变量'
function Foo(){
this.a = '我是局部变量';
this.say = function(){
setTimeout(function(){
console.log(this.a)
console.log(this)
}.bind(this), 2000);
}
}
var foo = new Foo()
foo.say() // '我是局部变量', Foo { a: '我是局部变量', say: [Function] }
上面代码,利用 bind()
将 this
绑定到这个函数上
在 bind(arg1, arg2)
被调用时,会创建一个新函数,这个新函数的 this
,都是 arg1
,也就是第一个参数。
与 bind
相似的方法还有两个:apply()
,call()
,他们的共同点:
- 三者都是用来改变函数的
this
对象的指向的; - 三者第一个参数都是this要指向的对象,也就是想指定的上下文
- 三者都可以利用后续参数传参;
不同点:
apply
和call
基本类似,他们的区别只是传入的参数不同;call
方法接受的是若干个参数列表,而apply
接收的是一个包含多个参数的数组。bind
是创建一个新的函数,我们必须要手动去调用;而其余两者都是立即执行