总结了自己平时使用的 this 判断方法,希望对大家的学习和工作有所帮助。
决策树
通用决策树:
if (this 位于非箭头函数中) {
if (函数使用 new 调用,即作为构造函数被调用) {
[this 指向新创建的对象]
} else if (函数使用 . 调用,即作为对象方法被调用) {
[this 指向 . 之前的对象]
} else {
if (严格模式) {
[this 为 undefined]
} else {
[this 为 null]
[但,使用 undefined 或者 null 指定 this 时,this 指向全局对象]
[this 指向全局对象]
}
}
} else if (this 位于箭头函数中) {
[词法分析时,函数所处作用域的 this]
} else {
[this 指向全局对象]
}
另外,
在严格模式下:
+ 如果手动指定了 this 且 this 是原始值,则 this 不再经历从原始值向原始值包装对象的转化
在非严格模式下:
+ 使用布尔值,字符串,数字等原始值指定 this 时,this 指向原始值所对应的包装对象
+ 使用 undefined 或者 null 指定 this 时,this 指向全局对象
严格模式下的决策树
严格模式会成为趋势,为了方便查看,也写一个严格模式下的 this
决策树:
if (this 位于非箭头函数中) {
if (函数使用 new 调用,即作为构造函数被调用) {
[this 指向新创建的对象]
} else if (函数使用 . 调用,即作为对象方法被调用) {
[this 指向 . 之前的对象]
} else {
[this 为 undefined]
[如果手动指定了 this,那么 this 就是指定的值,不再对其进行对象包装]
}
} else if (this 位于箭头函数中) {
[词法分析时,函数所处作用域的 this]
} else {
[this 指向全局对象]
}
示例
函数作为构造函数被调用
'use strict'
function C(num) {
this.num = num
}
const c = new C(20)
console.log(c.num) // 20
- 函数使用 new 调用? 是
this
指向新创建的对象。
函数作为对象方法被调用
'use strict'
const obj = {
num: 20,
f: function () {
return this
}
}
console.log(obj.f() === obj) // true
'use strict'
function f() {
return this
}
const obj = {
num: 20,
f
}
console.log(obj.f() === obj) // true
- 函数使用 new 调用? 否
- 函数使用 . 调用? 是
this
指向 . 前的对象。
函数被直接调用
function f() {
return this
}
f()
console.log(f() === this) // true
- 函数使用 new 调用? 否
- 函数使用 . 调用 ? 否
- 严格模式?否
this
指向全局对象。
'use strict'
function f() {
return this
}
f()
console.log(f() === undefined) // true
- 函数使用 new 调用? 否
- 函数使用 . 调用? 否
- 严格模式?是
this
为 undefined
。
还有种让人迷惑的直接调用:
'use strict'
const obj = {
num: 20,
f: function () {
// 定义 g 之后就被调用了,这也是直接调用
function g() {
return this
}
return g()
}
}
console.log(obj.f() === undefined) // true
- 函数使用 new 调用?否
- 函数使用 . 调用?否
- 严格模式?是
this
指向 undefined
。
函数
g
在匿名函数中声明并被调用了。分清楚g
的调用和f
的调用,就很容易明白了。
通过 call()
/ apply()
/ bind()
调用
'use strict'
const obj = {
num: 20,
f: function () {
return this
}
}
const objAnother = {}
console.log(obj.f.call(objAnother) === objAnother) // true
obj.f.call(objAnother)
实际上等同于 objAnother.f()
。
- 函数使用 new 调用?否
- 函数使用 . 调用?是
this
指向 . 前的对象。
'use strict'
function f () {
return this
}
console.log(f.call(1024)) // 1024
- 函数使用 new 调用? 否
- 函数使用 . 调用? 否
- 严格模式?是。那么,不再对
this
进行对象包装
this
为 1024
。
function f () {
return this
}
console.log(f.call(1024)) // [Number: 1024]
- 函数使用 new 调用? 否
- 函数使用 . 调用? 否
- 严格模式?否。
this
指定为原始值,进行对象包装
this
指向包装对象 [Number: 1024]
。
// 代码运行在 Node 模块模式中
function f () {
return this
}
console.log(f.call(null) === global) // true
console.log(f.call(undefined) === global) // true
- 函数使用 new 调用? 否
- 函数使用 . 调用? 否
- 严格模式?否。
this
指定为undefined
或null
。this 指向全局对象。
this
指向指向全局对象。
后记
this
决策树在应对难以判断的 this
指向问题时,很有用。
如果大家有更好的方式,欢迎讨论。