JavaScript this 指向七步口诀详解

作者:拾光时间:2026-10-25 01:21:15浏览:587

本文通过七步口诀系统讲解JavaScript中this的指向规则,涵盖箭头函数、new、bind、apply、call及直接调用等场景。详细对比严格模式与非严格模式下的差异,并结合代码示例与练习题,帮助开发者彻底掌握this绑定逻辑。

前言

掌握本文总结的七步口诀,即可彻底理清 JavaScript 中 this 的指向逻辑。

口诀顺序为:箭头函数、new、bind、apply 和 call、对象点调用(obj.)、直接调用、不在函数中。

依据口诀顺序判断,只要满足前述任一场景,即可确定 this 的具体指向。

下文将按口诀顺序逐一详解,示例代码均在 Chrome 控制台环境中运行。

文末附有精心设计的练习题,用于巩固学习成果,建议动手实践。

1. 箭头函数

箭头函数排在首位,因为其 this 指向固定不变。只要当前函数定义为箭头函数,无需参考后续规则,即可确定其 this 指向。

箭头函数的 this 继承自定义时外层作用域的 this。这里有两个关键点:

  1. 箭头函数在定义时,其 this 指向即已确定。
  2. 箭头函数内部的 this 始终指向外层作用域的 this。

因此,要确定箭头函数的 this,需先明确外层 this 的指向,并继续在外层应用七步口诀进行推导。

2. new

当使用 new 关键字调用函数时,函数内部的 this 始终指向 JS 引擎创建的新对象。

读者可能会疑惑:“如果使用 new 调用箭头函数,是否会改变箭头函数的 this?”

我们在控制台进行验证。


func = () => {}
new func() // throw error

从控制台输出可知,箭头函数不能作为构造函数使用,因此不能与 new 关键字配合执行。

3. bind

bind 方法对应 Function.prototype.bind()。

多次连续调用 bind 时,仅第一次 bind 指定的值生效。

易错点


function func() {
  console.log(this)
}

func.bind(1).bind(2)() // 1

箭头函数中的 this 不会被修改

bind 与 new 的交互

易错点


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 不会被修改

易错点


func = () => {
  // 这里 this 指向取决于外层 this,参考口诀 7 「不在函数里」
  console.log(this)
}

func.apply(1) // Window,口诀 1 优先

bind 函数内部的 this 不会被修改

易错点


function func() {
  console.log(this)
}

boundFunc = func.bind(1)
boundFunc.apply(2) // 1,口诀 3 优先

5. 欧比届点(obj.)


function func() {
  console.log(this.x)
}

obj = { x: 1 }
obj.func = func
obj.func() // 1

此处不再通过代码验证箭头函数和 bind 的优先级更高,有兴趣的读者可自行尝试。

6. 直接调用

若函数不满足前述场景且被直接调用,this 将指向全局对象。在浏览器环境中,全局对象为 Window;在 Node.js 环境中,全局对象为 Global。

先来看一个简单示例。


function func() {
  console.log(this)
}

func() // Window

再看一个复杂示例,外层 outerFunc 仅起迷惑作用。


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 均指向全局对象。


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()

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

前言

在严格模式下,执行相同代码进行对比。请注意需一次性将所有代码复制粘贴至控制台,才能启用严格模式(因为第一行的 "use strict" 仅对后续代码生效)。


"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()

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

前言

七步口诀在严格模式和非严格模式下均完备,区别仅在于非严格模式下 null 或 undefined 会被转换为全局对象。因此,未将此特殊情况列入口诀中。

做题复习

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

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


function func(num) {
  this.count++
}

func.count = 0
func(1)

答案

func.count 值为 0。

根据口诀,func() 调用属于第 6 类「直接调用」。在非严格模式下,this 指向全局对象,与 func 对象无关,因此 func.count 保持不变。非常简单。

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


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指向内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

作者最新文章