对于JavaScript中的this指向问题,一直是新手理解中的一个难点和易混淆的点
本文就我个人经验,对辨别this指向问题提出一些实操性、流程性的判断依据
真言①:谁调用,this指向谁
逻辑说明
看几个实例
1 | const obj = { |
上述案例还可更进一步
1 | const obj = { |
这里打印出的this指向全局,严格模式下为 unedfined
因为 console.log
发生的位置在 anotherFn
,obj.sayHi
调用的上下文确实是 obj 对象,但anotherFn
其实是没有调用上下文的,根据规范,非严格模式下,未指定上下文的,上下文为全局对象
一个小证明
这里再补一个谁调用指向谁的小证明:
1 | function checkThis() { |
这个小证明基于一个关于严格模式的事实:严格模式下,this 不发生隐式回退,也就是不指定调用上下文的,就为undefined
上面的这个函数,内部声明了启用严格模式
如果直接调用,最终查找到的其实也是window上的checkThis函数,但因为没有指定调用方,所以 this === undefined
如果带上window这个上下文调用,this === WindowObject
真言②:箭头函数this指向定义箭头函数的词法作用域
箭头函数没有this绑定,而是从函数定义时的词法作用域中查找this(静态作用域绑定
OR词法作用域绑定
)的,其查找过程与普通变量在作用域链上的查找过程类似
某行代码的词法作用域也可以不标准但通俗地理解为:这行代码在编写的时候所在的作用域;与之相对的动态作用域则是:不管你程序员代码如何摆放的,作用域都得等执行时根据上下文或是否调用绑定等因素确定,并且显著的一个特征是:在一连串的函数调用中,调用链的某个节点可以访问之前节点上的本地变量
无论是把函数放到别的对象中调用,还是直接暴力bind上下文,箭头函数都不会屈服
以下是将上例改为箭头函数
1 | const obj = { |
真言③:构造函数是个例外
最初的例子再改个调用方式
1 | const obj = { |
构造函数会创建新的对象作为执行构造函数时的上下文
如果构造函数没有返回新对象,这个创建的对象就是new后的实例
附言①:显式指定 this
有很多显而易见的方法可以指定 thisArg
如:
- bind 函数
- call 函数
- apply 函数
还有一些可能不是很常用的,但也可以绑定 thisArg
如:
- map
- forEach
- every
- filter
- some
等
附言②:元素绑定的事件回调
元素绑定的事件回调中,this 指向绑定事件的元素本身
附言③:顶级作用域的this ?
对于Browser来说,顶级作用域里的this(也就是最外层代码的this) 指向的是 WindowObject
而对于Nodejs,顶级作用域中的this指向的是module.exports
对象
即:
1 | // browser 环境 |
自测①
1 | const myObj = { |
第一个 myObj.print() 的输出为 bar bar undefined bar
第二个 pring() 的输出为 undefined undefined undefined undefined