JavaScript中的this指向是初学者常常难弄懂的知识点,也常常作为考察点出现在前端面试题、笔试题中。这里和大家一起弄懂this,如有错误,欢迎指出。
首先我们要知道的是,this是函数内部存在的特殊对象,在大部分情况下,函数运行的方式决定了this绑定的值(运行时),可以分为以下五种:
- 作为普通函数执行。
- 作为对象方法执行。
- 作为构造函数执行。
- 通过
call、apply、bind绑定this的方法执行。 - 作为箭头函数执行。
作为普通函数执行
我们来看下面的代码
var a = 1
function fn() {
console.log(this.a)
}
fn()
这里的fn没有被任何对象调用,只是作为普通函数在全局作用域下执行,因此this指向全局作用域window(在浏览器中运行),而在全局作用域中通过var关键字声明的变量会被挂载到全局作用域中,所以执行fn输出1。
注意:通过
let、const声明的变量不会被挂载到全局作用域当中
作为对象方法执行
当对象调用方法时,this便指向对象本身:
const obj = {
a: 2,
sayA(): {
console.log(this.a)
}
}
obj.sayA()
这里的sayA作为obj对象的方法被调用了,因此函数sayA的this指向obj对象,而obj恰好有个变量为a,所以这里执行obj.sayA输出2
作为构造函数执行
看过红宝书的帅哥美女们应该非常熟悉,当使用new关键字来创建一个构造函数的实例时,会执行如下操作:
- 在内存中创建一个新的对象。
- 这个新对象内部的
[[Prototype]]指针被赋值为构造函数的prototype属性 - 构造函数内部的
this被赋值为这个新对象(即this指向新对象) - 执行构造函数内部的代码(给新对象添加属性)
- 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。
由第三步可知,当作为构造函数时执行,this指向新创建的对象,即构造函数的实例。我们来看下面的代码:
function Fn(a) {
this.a = a
}
const instance = new Fn(3)
console.log(instance.a)
由于instance是Fn的实例,所以instance.a的值就是this.a,因此这里输出3。
通过call、apply、bind绑定this的方法执行
Function的原型方法中,call、apply、bind这三个方法都能显式地修改this的指向,它们接收的第一个参数即修改后this指向的对象。我们来看下面的代码:
var a = 1
function fn() {
console.log(this.a)
}
const obj = {
this.a = 2
}
fn.call(obj)
fn.apply(obj)
fn.bind(obj)()
上面fn分别被call、apply、bind三个方法修改了this的指向并执行了三次,因为this指向obj所以输出为2 2 2 。
作为箭头函数执行
ES6新加入了箭头函数,在箭头函数中,this引用的是定义箭头函数的上下文,即在箭头函数定义时,this的值就跟着确定下来了,且不会再被改变。我们来看下面的代码:
var a = 1
const obj = {
a: 2
}
const sayA = () => {
console.log(this.a)
}
sayA()
sayA.call(obj)
sayA是在全局作用域中定义的,所以this指向全局作用域,执行sayA输出1,又因为箭头函数的this的值不会被改变,所以sayA.call(obj)企图将sayA的this指向修改为obj的操作是无效的,执行后仍然输出1。
看到了这里的朋友是不是觉得this指向也不过如此?相比HTTP的几十种状态码,5种类型对咱们来说简直就是手到擒来。最后,感谢大家的支持,Thanks♪(・ω・)ノ。