写在前面
先看这个函数,它们的输出为什么会不同?
//例1
var obj = {
foo: function () {
console.log(this.bar);
},
bar: 1
};
var foo = obj.foo;
var bar = 2;
obj.foo() // 1
foo() // 2
造成不同的原因是this的指向不一样。this指的是函数运行时所在的环境。那么对obj.foo() 来说,它的运行环境在obj这个函数中,而对于foo() 这个函数来说,它的运行环境是全局环境,全局环境中bar被赋予了新的值2,所以它打印结果为2。
为什么this指向不一样?
需要理解数据结构。
1、属性的值为基本类型(值类型)
//例2
var obj = {foo : 5}
将一个对象{foo : 5}赋值给一个变量obj,相当于把这个对象的内存地址赋值给变量obj。 原始对象以字典结构保存,也就是每一个属性名对应一个属性描述对象,那么上面的对象中foo属性实际上是以下面的方式保存的:
那么,foo属性的值实际上是保存在属性描述对象的value中。
2、 属性的值为函数
//例3
var obj = { foo: function () {} };
这时,引擎会将函数单独保存在内存中,然后再将函数的地址赋值给foo属性的value属性。
这时函数是一个独立的值,它可以在不同的环境(上下文)中执行。
//例4
//在obj中执行:
obj.foo();
//单独执行
var foo = obj.foo;
foo();
既然函数可以在不同环境中执行,那么就需要获得当前环境。这是this就出现了,用它来代指函数的运行环境。
回到本文一开始的问题,obj.foo中的this的环境就是obj本身,obj中的bar=1;当执行var foo = obj.foo时,foo指的就是函数本身,该函数所在的环境是全局环境,this指向的就是全局环境,全局环境中的bar=2。
箭头函数中的this
ES6中新增了箭头函数,一方面简化了回调函数。另一方面,也是最值得注意的地方是:箭头函数改变了this的指向。
箭头函数中的this固定指向绑定定义时所在的环境,而不是执行时的环境。
参考文章 JavaScript 的 this 原理
2020.10.10 补充
- “不管是什么场合,this都有一个共同点:它总是返回一个对象。”
- “简单说,this就是属性或方法‘当前’所在的对象。”
- 执行环境也是一个对象,this的指向也可以说是指向它的执行环境。