JS 中的 this 是一个很容易让人迷糊的概念,本文主要总结了各种情况下的 this 指向。
全局环境中的 this
全局环境中的 this 总是指向全局对象 window 上的。
this.a1 = 10; |
非箭头函数中的this
需要记住一点:在一个函数上下文中,函数中的 this 始终是由函数的调用者提供,若不存在调用者,则非严格模式下 this 指向全局顶级对象(浏览器中为 window 对象),而严格模式下 this 为 undefined。接下来看几个例子:
var person = { |
很明显,函数的调用者是 person,所以 this 指向 person。
看起来很简单,再看个例子试试:
var name = 'Global window' |
注意,判断函数中 this 的指向,是在执行的时候决定的,而语句 greet()
在执行时,greet
函数并没有调用者,所以,this 指向全局对象 window
,所以输出 window.name
。
而语句 personMack.greet()
在执行时,greet 的调用者为 personJack
,所以 this.name
指向 personJack.name
。
再看另一个例子:
var name = 'Global'; |
很明显,这次 getName
的调用者是 person.full
,this 指向它。
严格模式(use strict)下的 this
在上一节中提到,如果函数的调用者不存在,函数中的 this 则指向全局变量 window,这样无疑在有些情况下会出现难以检查的错误:
var name = 'global'; |
在上面的例子中,由于 window 对象恰好存在一个 name 属性,所以也不会报错。但是,如果代码规格比较大,定位错误无疑是非常困难的。
使用严格模式,如果函数不存在调用者,this 将会指向 undefined 而不再是全局对象 window 了:
|
此时会抛出错误,很容易定位到错误的位置。
关于严格模式的更多细节,请查看 MDN
箭头函数中的this
箭头函数中的 this
指向其在 声明时所在的最近的一个非箭头函数 的 this
。并且箭头函数的 this 指向在箭头函数声明后是不会且不能改变的。
function a() { |
在上面的例子中,最内层箭头函数声明时,最近的非箭头函数是 f(a) 而 f(a) 在执行时没有调用者,this 指向全局变量 window,所以箭头函数的 this 也指向全局变量 window。
如果改变 f(a) 中 this 的指向呢:
var obj = { |
前面提到“箭头函数的 this 指向在箭头函数声明后是不会且不能改变”,这和上面的例子并不冲突。也就是说箭头函数的指向在声明阶段就已经确定了,比如在上面的例子,箭头函数中的 this 在声明的时候就确定指向了 f(a)
中的 this,但是 f(a)
中的 this 指向的目标可能是在执行阶段才确定的,再看个例子:
function b() { |
从上面的例子可以看出,箭头函数中的 this 始终指向 f(a) 中的 this。
参数为函数时的 this
这种情况看起来很绕,实际上掌握了上面几点后就很简单,看下面的例子:
var obj = { |
在调用 obj.getEven() 时,需要了解 map 内部是如何执行的,下面是 map 的一个 polyfill:
if (Array.prototype.map === undefined) { |
从代码中可以看出,函数在调用时并没有调用者,因此 this 指向 window。而 getTreble 中参数为箭头函数,this 指向和其调用方式没有关系,都指向 obj。
bind、call、apply
这三个函数都是用于改变函数中 this 的指向,具体概念及接口不再说明,这里只举一个例子:
var obj = { |
还有一个场景,如果想要我们的匿名函数能够访问到指定对象,就可以使用 bind,看下面的例子:
var a = 10; |