findxc / blog

88 stars 5 forks source link

this 的值的一些例子 #42

Open findxc opened 3 years ago

findxc commented 3 years ago

你不知道的JavaScript(上卷) - 图书 - 豆瓣 这本书对词法作用域和 this 写得挺详细的。

要知道 this 取值,首先要先理解词法作用域,因为对于箭头函数, this 值是取决于词法作用域的,而对于其它函数 this 值则取决于调用方式。

注意,以下例子均不考虑使用 evalwith 的场景,也不考虑严格模式。

词法作用域

可以理解为静态的、固定的,作用域在书写代码时就已经被确定了。

name = 'xc_1' // ②

function log() {
  console.log(name)  // ①
}

function run() {
  const name = 'xc_2'
  log()
}

run()

在 ① 处 name 这个变量在函数 log 内未定义,所以会往外层作用域去找,然后找到 ② 处定义的 name

这个是只和代码书写有关的。接下来无论函数 log 在哪里被调用以及如何被调用,最终的打印值都会是 xc_1

箭头函数中的 this 值

值为词法作用域中箭头函数所在位置的 this 。

// ②

const log = () => {
  console.log('this: ', this)  // ①
}

log()

const obj = { name: 'xc' }

log.bind(obj)()

① 处的 this 是 ② 处的 this 值,就是 Window

为什么 bind 没有改变 this 的值呢,因为这个 this 是词法作用域决定的,书写代码的时候,作用域就已经固定了,后续无法改变。

function wrapper() {
  // ②
  const log = () => {
    console.log('this: ', this)  // ①
  }
  return log
}

wrapper()()

const obj = {
  name: 'xc',
  wrapper,
}

obj.wrapper()()

wrapper.bind(obj)()()

① 处的 this 是 ② 处的 this 值,而 ② 处的 this 值取决于函数 wrapper 被如何调用。

可以用 Babel 来帮助理解箭头函数中的 this ,见下图。var _this = this 这种写法也是箭头函数这个语法出来之前很常见的一种写法。

image

非箭头函数的 this 值

在调用时 this 值是动态绑定的, this 值取决于调用方式,千万不要再去想词法作用域。

判断时按照以下顺序去判断即可。

先看有没有显示绑定,如果有显示绑定 this 就是显示绑定的那个对象。显示绑定指 bindcallapply

function log() {
  console.log('this: ', this)
}

const obj = { name: 'xc' }

log.bind(obj)()

没有显示绑定的话再看有没有隐式绑定,如果有的话就是隐式绑定的那个对象。隐式绑定指 a.b() 的方式来执行函数 b 。隐式绑定的话只用关心最近的那个调用对象。

function log() {
  console.log('this: ', this)
}

const obj = {
  name: 'xc_1',
  log,
  inner: {
    name: 'xc_2',
    log,
  },
}

obj.log()

obj.inner.log()

如果隐式绑定也没有,也就是函数是直接调用的,就是指向 Window

function log() {
  console.log('this: ', this)
}

function wrapper() {
  log()
}

wrapper()

如果还想知道更多

function log() {
  console.log('this: ', this)
}

const obj = {
  name: 'xc',
  log,
}

obj.log()
// 比如下面这两种奇奇怪怪的
;(false || obj.log)()
;(obj.log = obj.log)()

可以参见 JavaScript深入之从ECMAScript规范解读this · Issue #7 · mqyqingfeng/Blog · GitHub根治JavaScript中的this-ECMAScript规范解读 | leon的后花园 去读读规范。

findxc commented 3 years ago

补充一个有很多举例的文章:JavaScript: What is the meaning of this?