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
指向函数执行的环境对象。