JS 中 this 指向问题


转载于:博主链接

相信我,只要记住本文的 7?? 步口诀,就能彻底掌握 JS 中的 this 指向。
先念口诀:箭头函数、new、bind、apply 和 call、欧比届点(obj.)、直接调用、不在函数里。
按照口诀的顺序,只要满足前面某个场景,就可以确定 this 指向了。
接下来按照口诀顺序对它们进行详解,文中示例代码都运行在 Chrome 的 Console 控制台中。
文末有精心准备的练习题,用于检验学习成果,别忘了试试~

  1. 箭头函数
    箭头函数排在第一个是因为它的 this 不会被改变,所以只要当前函数是箭头函数,那么就不用再看其他规则了。
    箭头函数的 this 是在创建它时外层 this 的指向。这里的重点有两个:

创建箭头函数时,就已经确定了它的 this 指向。
箭头函数内的 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 不会被修改

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

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

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 })()
  1. 不在函数里
    不在函数中的场景,可分为浏览器的