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.age 为 18 可以看出,以构造函数的形式执行函数时,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. 后面的 call 和 apply 指定的 this 是对象 obj, sayHello 函数执行这两个方法时,this 指向了 obj.
bind 方法的第一个参数也是指定的 this, 执行 bind 方法,返回一个拥有指定 this 的函数。上面代码中的 hi 指向一个函数,这个函数是 this 为 obj 的 sayHello.
箭头函数
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() 是方法调用,此时,foo 的 this 指向的是对象 obj. 而 foo 中的箭头函数用到的 this 是从箭头函数的外部(即 foo)拿到的,也指向 obj.
对象 obj 的 foo 赋值给了变量 b, let b = obj.foo 相当于下面的代码:
let b = function () {
return () => {
console.log(this.hello)
}
}
接下来执行 b, 把返回的箭头函数赋值给 c. 此时,执行 b 是一次函数调用,函数 b 的 this 指向的是它的运行环境 window. 箭头函数拿到的 this, 是它外层函数的 this, 也就是 window.
总结
this 指向函数执行的环境对象。