JavaScript 中的this指向
问题真的是被反反复复的说起,不管是前端新人还是职场老鸟,总会被这个 this
搞的蒙圈,而它又是面试特别喜欢问的问题,所以每次面试前都要复习一下,有点无奈。针对这种情况,我只想说一句“我太难了”。
其实要搞懂 this
指向,就要先搞清楚它的存在场景,主要就是三大场景:
- 普通函数中
- 箭头函数中
- bind,call,apply
普通函数中的 this
普通函数就是非箭头函数,看 this
指向就要看它是怎么被调用的,普通函数有三种调用方式:
- 直接调用,如:
func()
- 对象调用,如:
obj.func()
- 使用 new,如:
new func()
直接调用
对于直接调用的函数,就不用多想了,其内部的 this
都指向的是全局 Window
对象
function func() {
console.log(this.a)
}
var a = 123
func() // 123
哪怕你的函数在别的函数内部调用,只要是直接调用的,this
都指向Window
,比如这样:
function func1() {
console.log(this.a)
}
var a = 123
function func2() {
var a = 456
func1()
}
func2() // 123
对象调用
对于对象调用,这样的obj.func()
,那 this 指向的就是前面的对象,即obj
,此时只需要记住,谁调用了函数,谁就是 this。示例:
function func() {
console.log(this.a)
}
var a = 123
var obj = {
a: 456,
func: func
}
obj.func() // 456
使用 new 调用
使用 new
调用后,this
被永远绑定在生成的实例上,不会被任何方法改变
function func() {
console.log(this.a)
}
var a = 123
var n = new func() // undefined,因为实例 n 上没有 a 属性
箭头函数中的 this
箭头函数中的this
,就更让人摸不着头脑了,其实箭头函数里是不存在 this
的,箭头函数中的 this
只取决包裹箭头函数的第一个普通函数的 this
,举个例子:
function func() {
return () => {
return () => {
console.log(this)
}
}
}
func()()() // Window
例子中,因为包裹箭头函数的第一个普通函数是 func
,所以此时的 this
是 Window
。
而且,箭头函数中的 this
值,取决于它定义时所在的对象,而不是使用时所在的对象,怎么理解这个呢,举个例子:
var obj = {
a: 123,
func: () => {
console.log(this.a)
}
}
var a = 456
obj.func()
我相信很多人都会做错例子中的题,都会觉得打印结果是123
,而正确答案应该是456
。因为箭头函数中的this
值取决于定义时的对象,而不是调用时的对象,这跟普通函数相反的。func
定义在对象obj
中,此对象不具备作用域,所以this
指向全局Window
。
bind,call,apply
这三个也不用多说,this
是第一个参数。这里重点说一下bind
,如果对一个函数进行多次 bind,那么最终this
指向谁?例子:
var a = { name: 'a' }
var b = { name: 'b' }
function func() {
console.log(this)
}
func.bind(a).bind(b)()
例子中的输出结果是a
而不是b
,记住不管我们给函数 bind 几次,func 中的 this
永远由第一次 bind 决定。而apply
和 call
因为绑定的同时就执行了函数,所以不支持这种链式绑定。