服务器之家:专注于服务器技术及软件下载分享
分类导航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服务器之家 - 编程语言 - JavaScript - js教程 - JavaScript中的this指向问题详解

JavaScript中的this指向问题详解

2022-03-03 17:02MoonBall js教程

这篇文章主要给大家介绍了关于JavaScript中this指向问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

相信我,只要记住本文的 7步口诀,就能彻底掌握 JS 中的 this 指向。

先念口诀:箭头函数、new、bind、apply 和 call、欧比届点(obj.)、直接调用、不在函数里。

按照口诀的顺序,只要满足前面某个场景,就可以确定 this 指向了。

接下来按照口诀顺序对它们进行详解,文中示例代码都运行在 Chrome 的 Console 控制台中。

文末有精心准备的练习题,用于检验学习成果,别忘了试试~

1. 箭头函数

箭头函数排在第一个是因为它的 this 不会被改变,所以只要当前函数是箭头函数,那么就不用再看其他规则了。

箭头函数的 this 是在创建它时外层 this 的指向。这里的重点有两个:

  1. 创建箭头函数时,就已经确定了它的 this 指向。
  2. 箭头函数内的 this 指向外层的 this。

所以要知道箭头函数的 this 就得先知道外层 this 的指向,需要继续在外层应用七步口诀。

2. new

当使用 new 关键字调用函数时,函数中的 this 一定是 JS 创建的新对象。

读者可能会有疑问,“如果使用 new 关键调用箭头函数,是不是箭头函数的 this 就会被修改呢?”。

我们在控制台试一下。

?
1
2
func = () => {}
new func() // throw error

从控制台中可以看出,箭头函数不能当做构造函数,所以不能与 new 一起执行。

3. bind

bind 是指 Function.prototype.bind() 。

多次 bind 时只认第一次 bind 的值

易错点

?
1
2
3
4
5
function func() {
  console.log(this)
}
 
func.bind(1).bind(2)() // 1

箭头函数中 this 不会被修改

?
1
 

bind 与 new

易错点

?
1
2
3
4
5
6
function func() {
  console.log(this, this.__proto__ === func.prototype)
}
 
boundFunc = func.bind(1)
new boundFunc() // Object true,口诀 2 优先

4. apply 和 call

apply() 和 call() 的第一个参数都是 this,区别在于通过 apply 调用时实参是放到数组中的,而通过 call 调用时实参是逗号分隔的。

箭头函数中 this 不会被修改

易错点

?
1
2
3
4
5
6
func = () => {
  // 这里 this 指向取决于外层 this,参考口诀 7 「不在函数里」
  console.log(this)
}
 
func.apply(1) // Window,口诀 1 优先

bind 函数中 this 不会被修改

易错点

?
1
2
3
4
5
6
function func() {
  console.log(this)
}
 
boundFunc = func.bind(1)
boundFunc.apply(2) // 1,口诀 3 优先

5. 欧比届点(obj.)

?
1
2
3
4
5
6
7
function func() {
  console.log(this.x)
}
 
obj = { x: 1 }
obj.func = func
obj.func() // 1

这里就不用代码例证箭头函数和 bind 函数的优先级更高了,有兴趣可自行尝试吧。

6. 直接调用

在函数不满足前面的场景,被直接调用时,this 将指向全局对象。在浏览器环境中全局对象是 Window,在 Node.js 环境中是 Global。

先来个简单的例子。

?
1
2
3
4
5
function func() {
  console.log(this)
}
 
func() // Window

来一个复杂的例子,外层的 outerFunc 就起个迷惑目的。

?
1
2
3
4
5
6
7
8
9
10
11
function outerFunc() {
  console.log(this) // { x: 1 }
 
  function func() {
    console.log(this) // Window
  }
 
  func()
}
 
outerFunc.bind({ x: 1 })()

7. 不在函数里

不在函数中的场景,可分为浏览器的 <script /> 标签里,或 Node.js 的模块文件里。

  1. 在 <script /> 标签里,this 指向 Window。
  2. 在 Node.js 的模块文件里,this 指向 Module 的默认导出对象,也就是 module.exports。

非严格模式

严格模式是在 ES5 提出的。在 ES5 规范之前,也就是非严格模式下,this 不能是 undefined 或 null。所以**在非严格模式下,通过上面七步口诀,如果得出 this 指向是 undefined 或 null,那么 this 会指向全局对象。**在浏览器环境中全局对象是 Window,在 Node.js 环境中是 Global。

例如下面的代码,在非严格模式下,this 都指向全局对象。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function a() {
  console.log("function a:", this)
  ;(() => {
    console.log("arrow function: ", this)
  })()
}
 
a()
 
a.bind(null)()
 
a.bind(undefined)()
 
a.bind().bind(2)()
 
a.apply()

非严格模式下执行结果为:

JavaScript中的this指向问题详解

在严格模式下,执行同样的代码进行对比。记住要一次性将所有代码复制粘贴到控制台中,才能运行在严格模式下(因为第一行 "use strict" 才会对后面的代码生效)。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"use strict"
 
function a() {
  console.log("function a:", this)
  ;(() => {
    console.log("arrow function: ", this)
  })()
}
 
a()
 
a.bind(null)()
 
a.bind(undefined)()
 
a.bind().bind(2)()
 
a.apply()

严格模式下执行结果为:

JavaScript中的this指向问题详解

七步口诀在严格模式下和非严格模式下都是完备的,只是在非严格模式下 null 或 undefined 会被转换为全局对象。所以我没有将这点列入口诀中。

做题复习

先背诵口诀再做题,“箭头函数、new、bind、apply 和 call、欧比届点(obj.)、直接调用、不在函数里”。

1. 下面代码执行后,func.count 值为多少?

?
1
2
3
4
5
6
function func(num) {
  this.count++
}
 
func.count = 0
func(1)

答案

func.count 值为 0。

按照口诀,func() 调用时属于第 6 类「直接调用」。在非严格模式下,this 指向全局对象。this 跟 func 一点关系都没有,所以 func.count 保持不变。so easy。

2. 以下箭头函数中 this 指向谁呢?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
obj = {
  func() {
    const arrowFunc = () => {
      console.log(this._name)
    }
 
    return arrowFunc
  },
 
  _name: "obj",
}
 
obj.func()()
 
func = obj.func
func()()
 
obj.func.bind({ _name: "newObj" })()()
 
obj.func.bind()()()
 
obj.func.bind({ _name: "bindObj" }).apply({ _name: "applyObj" })()

答案

// obj
// undefined
// newObj
// undefined
// bindObj

是不是很简单,你学废了吗?

总结

到此这篇关于JavaScript中的this指向问题的文章就介绍到这了,更多相关js中this指向内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://juejin.cn/post/6946021671656488991

延伸 · 阅读

精彩推荐
  • js教程js仿淘宝放大镜效果

    js仿淘宝放大镜效果

    这篇文章主要为大家详细介绍了js仿淘宝放大镜效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    屈小康11252021-12-21
  • js教程Vant+postcss-pxtorem 实现浏览器适配功能

    Vant+postcss-pxtorem 实现浏览器适配功能

    这篇文章主要介绍了Vant+postcss-pxtorem 实现浏览器适配,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    Heroin、9532022-01-17
  • js教程js实现鼠标切换图片(无定时器)

    js实现鼠标切换图片(无定时器)

    这篇文章主要为大家详细介绍了js实现鼠标切换图片,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    枫思然8172022-01-10
  • js教程three.js 实现露珠滴落动画效果的示例代码

    three.js 实现露珠滴落动画效果的示例代码

    这篇文章主要介绍了three.js 实现露珠滴落动画效果的示例代码,非常不错,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    稀土掘金11342022-01-24
  • js教程js基于canvas实现时钟组件

    js基于canvas实现时钟组件

    这篇文章主要介绍了js基于canvas实现时钟组件的方法,帮助大家更好的理解和使用JavaScript,感兴趣的朋友可以了解下...

    豫见陈公子11212022-01-19
  • js教程JS实现鼠标移动拖尾

    JS实现鼠标移动拖尾

    这篇文章主要为大家详细介绍了JS实现鼠标移动拖尾效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    day09962021-12-21
  • js教程js删除指定位置超链接中含有百度与360的标题

    js删除指定位置超链接中含有百度与360的标题

    最近需要将最近更新的部分内容删除,只要标题中包括百度与360的都给删除了,主要用到了jquery的each,需要的朋友可以参考下...

    JS教程网3762021-12-27
  • js教程一起来了解一下JavaScript的预编译(小结)

    一起来了解一下JavaScript的预编译(小结)

    这篇文章主要介绍了一起来了解一下JavaScript的预编译(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    前端布吉岛12022022-01-25