导航
导航
文章目录
  1. 前言
  2. 仅仅是“规则”
  3. 不仅仅是“规则”

JavaScript系列之this

前言

在JavaScript语言中存在一个this关键词,这个关键词指的是函数运行时所在的环境。由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。

前一个系列的作用域讲过,作用域运用的是词法作用域,意味着是编写时确定的,但this与其工作原理完全不同,它的指向并不是编写时确定的,而是运行时确定。

仅仅是“规则”

之前在阅读 You Don’t Know JS系列的: this & Object Prototypes中,将this的指向总结了几条规则:

函数调用方式与内部this指针关系:

  1. 直接调用:函数内部this指向全局对象window
  2. 通过对象使用点来调用:函数内部this指向调用对象
  3. 触发事件调用函数:函数内部的this指向触发事件的对象
  4. new的方式来调用:函数内部this指向本次函数执行时对应的一个匿名对象(以new的方式创建的函数,函数名的首字母一般以大写字母开始)
  5. 通过call的方法来间接调用方法:函数内部this指向call方法的第一参数对象,我们可以创建结构相同,但内容不同的对象

不仅仅是“规则”

参考了上面的规则发现,this的指向无论如何都逃脱不了上面的5大原则,那它们之前是否存在一定的规律呢,或者说是什么来决定this的指向的。

通常我们会对一下例子的结果没法准确的确定this指向:

1
2
3
4
5
6
7
8
9
10
11
var name = 'zhou';
var obj = {
name: 'shaw',
say: function () {
console.log(this.name);
}
}
obj.say();

var say = obj.say;
say();

上面的输出结果会是什么呢:

1
2
obj.say(); // 输出shaw
say(); // 输出zhou

为什么这里obj.saysay的输出结果会不一致呢?下面我们来一探究竟。

this的指向与数据在内存里的数据结构有关:

上面案例里的obj对象是如何在内存中存储的呢

1
2
3
4
5
obj.say-> {
[[value]]: say函数地址
[[write]]: true,
[[readable]]: true
}

实际上say函数并没有存储在obj对象中,它只存储了say函数的地址。

我们直接通过obj.say来调用函数,与obj.say赋值给say变量调用完全不同,因为obj中存储的是say函数的地址,我们进行赋值操作时直接将say函数地址直接赋值过去了,而不是我们想象的将obj.say引用赋值过去。