你好,我是 JavaScript 的 this

100 阅读3分钟

JavaScript 有个关键字 this, 时不时冒出来,让你猜一猜,“我到底指向谁?”

这个 this 指向 window, 那个 this 又是刚刚 new 出来的新对象,这里又冒出来一个指向 call 函数的第一个参数的。

到底什么鬼?一团乱麻。

线索

快刀斩乱麻,这里的快刀同学只会说一句话:"this 指向函数执行的环境对象。"

怎么理解

带着上面的线索,去几个场景,来看一看,this 在各种情况下,到底指向哪位。

函数调用

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

a() // window

在浏览器中,a 的执行环境即为 window, 所以 this 指向了 window.

方法调用

let obj = {
  b: function () {
    console.log(this)
  }
}

obj.b() // obj

当作为对象的方法时,函数的 this 指向其所属对象。

构造函数

window.age = 100 

function GirlFriend () {
  this.age = 18
}

const girlFriend = new GirlFriend()
console.log(girlFriend.age) // 18

girlFriend.age18 可以看出,以构造函数的形式执行函数时,this 指向其返回的对象。

改变 this 指向

window.hello = 'Hello, I am window.'

let obj = {
  hello: 'Hello, I am obj.'
}

function sayHello () {
  console.log(this.hello)
}

sayHello() // 'Hello, I am window.'
sayHello.call(obj) // 'Hello, I am obj.'
sayHello.apply(obj) // 'Hello, I am obj.'

const hi = sayHello.bind(obj)
hi() // 'Hello, I am obj.'

call 方法和 apply 方法接收的第一个参数,是一个为函数指定的 this. 上面的代码中,第一次函数调用形式执行 sayHello, this 指向的是 window. 后面的 callapply 指定的 this 是对象 obj, sayHello 函数执行这两个方法时,this 指向了 obj.

bind 方法的第一个参数也是指定的 this, 执行 bind 方法,返回一个拥有指定 this 的函数。上面代码中的 hi 指向一个函数,这个函数是 thisobjsayHello.

箭头函数

window.hello = 'Hello, I am window.'

let obj = {
  hello: 'Hello, I am obj.',
  foo: function () {
    return () => {
      console.log(this.hello)
    }
  }
}

let a = obj.foo()
a() // 'Hello, I am obj.'

let b = obj.foo
let c = b()
c() // 'Hello, I am window.'

箭头函数没有自己的 this, 当箭头函数内部出现 this, 可将它理解为一个变量——“我没有这个变量,去我的外面一层找一找有没有”。所以,箭头函数的 this, 指向的是定义箭头函数时的外部环境。

上面代码中,对象 obj 的方法 foo, 返回一个箭头函数,该箭头函数打印 this.hello.

变量 a 的值是 obj.foo() 的返回值,即为箭头函数。obj.foo() 是方法调用,此时,foothis 指向的是对象 obj. 而 foo 中的箭头函数用到的 this 是从箭头函数的外部(即 foo)拿到的,也指向 obj.

对象 objfoo 赋值给了变量 b, let b = obj.foo 相当于下面的代码:

let b = function () {
  return () => {
    console.log(this.hello)
  }
}

接下来执行 b, 把返回的箭头函数赋值给 c. 此时,执行 b 是一次函数调用,函数 bthis 指向的是它的运行环境 window. 箭头函数拿到的 this, 是它外层函数的 this, 也就是 window.

总结

this 指向函数执行的环境对象。