Javascript之this用法
this是Javascript语言的一个关键字。随着使用场合的不同,this的值会发生变化。
但是有一个总的原则,那就是this始终指的是,调用函数的那个对象。
在全局作用域下
在浏览器环境下:全局作用域下,this 指向 Window 对象.
在 node 环境下:全局作用域下,this 指向 global 对象。
严格模式,在 node 环境下:遵循严格模式的规范,this 不再指向全局对象。
函数对象作用域下
|
|
严格模式,在 node 环境下:
作为对象方法的调用
作为对象方法时,this 指向该对象。
注意到:在函数体内使用的、在函数体外定义(声明)的变量,是 传引用 的。
在回调函数里面会遇到一些坑
|
|
执行这段代码我们会发现两次打印出来的 this
是不一样的:
第一次是 foo2
中直接打印 this
,这里指向 obj
这个对象,
但是在 setTimeout
中执行的 this.foo
,却指向了全局对象.
把 this.foo
当作一个参数传给 setTimeout
这个函数,就像它需要一个 fun
参数,在传入参数的时候,其实做了个这样的操作 fun = this.foo
,这里我们直接把 fun
指向 this.foo
的引用;执行的时候其实是执行了 fun()
所以已经和 obj
无关了,它是被当作普通函数直接调用的,因此 this
指向全局对象。
解决:
为了解决这个问题,我们可以利用 闭包 的特性来处理:
可以看到直接用 this
仍然是 Window
;因为 foo2
中的 this
是指向 obj
,我们可以先用一个变量 _this
来储存,然后在回调函数中使用 _this
,就可以指向当前的这个对象了;
setTimeout 的另一个坑
如果直接执行回调函数而没有绑定作用域,那么它的 this
是指向全局对象(window
),在严格模式下会指向 undefined
,然而在 setTimeout
中的回调函数在严格模式下却表现出不同:
按理说我们加了严格模式,foo 调用也没有指定 this
,应该是出来 undefined
,但是这里仍然出现了全局对象,难道是严格模式失效了吗?
并不,即使在严格模式下,setTimeout
方法在调用传入函数的时候,如果这个函数没有指定了的 this
,那么它会做一个隐式的操作—-自动地注入全局上下文,等同于调用 foo.apply(window)
而非 foo()
;
当然,如果我们在传入函数的时候已经指定 this
,那么就不会被注入全局对象,比如: setTimeout(foo.bind(obj), 1);
;
箭头函数
在 ES6 的新规范中,加入了箭头函数,它和普通函数最不一样的一点就是 this
的指向了,
上文我们使用闭包来解决 this
的指向问题,但如果用上了箭头函数就可以更完美的解决了:
可以看到,在 setTimeout
执行的函数中,本应该打印出在 Window
,但是在这里 this
却指向了 obj
,原因就在于,给 setTimeout
传入的函数(参数)是一个箭头函数:
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
关键点就是,箭头函数内的 this
执行定义时所在的对象,就是指向定义这个箭头函数时作用域内的 this
,也就是 obj.foo2
中的 this
,即 obj
;所以在执行箭头函数的时候,它的 this
-> obj.foo2 中的 this
-> obj
;
简单来说, 箭头函数中的 this 只和定义它时候的作用域的 this 有关,而与在哪里以及如何调用它无关,同时它的 this 指向是不可改变的。
call / apply / bind
js 中的函数对象,其 prototype 中定义了如下三个函数:
bind 的 this 对 new 关键字无效,但其他实参有效:
要注意,=> 语法下的 this 不受影响,该语法下 this 视为 const 变量,不接受修改。