乐趣区

我真的不懂 this — JavaScript是一门玄学

[未完成] 作为一名前端,很惭愧,我不懂 this。平常写代码我们多多少少会碰到使用 this,可是扪心自问下,你真的懂它吗?既然不懂,那就应该多学习并且查阅资料搞懂它。
介绍 `this` 的文章市面上很多,参差不齐,这边推荐几篇个人认为有价值的文章,供各位学习参考。注意,这几篇文章都是需要耐心阅读的,只是扫一遍并不能理解其重点。

MDN — this 阮一峰 — this 关键字 The Simple Rules to‘this’in Javascriptmqyqingfeng — JavaScript 深入之从 ECMAScript 规范解读 this
这篇文章我不会从不同情形下分析 this 指向的思路, 因为想充分理解 this,需要从 JS 的执行环境、闭包、作用域、构造函数等等道来。
this 的实质?
阮老师的这篇文章里介绍说 this 的设计与内存中的数据结构有关。比如有个对象
var obj = {
name: ‘ 可爱蛋 ’
}
JavaScript 引擎会先在内存中生成一个对象 {name: ‘ 可爱蛋 ’},然后将这个对象的内存地址赋值给 obj 而这个对象在内存中是以如下形式保存的
{
name: {
[[value]]: ‘ 可爱蛋 ’,
[[writable]]: true,
[[enumerable]]: true,
[[configurable]]: true,
}
}
如果我想取 obj.name,引擎需要先在 obj 中拿到内存地址,然后在该地址中读取上面这个对象信息,name 属性值即为 value 值 这个情况比较简单,但是当属性值是一个函数的时候
var obj = {
getName: function() {}
}
这时候,引擎会将属性值(这个 function) 单独存在内存中,然后将函数的内存地址赋值给 getName 的 value 属性, 即此时这个对象在内存中是
{
name: {
[[value]]: 函数的地址,
[[writable]]: true,
[[enumerable]]: true,
[[configurable]]: true,
}
}
到了这里,this 是时候出现了。因为函数是一个单独的值,所以可以在不同的环境下执行,所以需要一套机制,能够使得在函数体内部获得当前的运行环境 =》言下之意,this 的出现是为了在函数体内部指代当前函数的执行环境的。为什么要在函数体内部知道当前函数的执行环境呢?因为在函数内部我们会使用外部的变量。emmm, 这不是闭包的知识点了嘛,头晕,我不懂 this
this 的使用场合
MDN — this 这篇文章详细的分析了 this 的使用场合分以下几种情况,这里我做了一张思维导图。

读完文章,好啊,我以为我弄懂 this 了,然后我找了一道面试题试试水 相学长 — 从这两套题,重新认识 JS 的 this、作用域、闭包、对象
var name = ‘window’

var person1 = {
name: ‘person1’,
show1: function () {
console.log(this.name)
},
show2: () => console.log(this.name),
show3: function () {
return function () {
console.log(this.name)
}
},
show4: function () {
return () => console.log(this.name)
}
}
var person2 = {name: ‘person2’}

person1.show1()
person1.show1.call(person2)

person1.show2()
person1.show2.call(person2)

person1.show3()()
person1.show3().call(person2)
person1.show3.call(person2)()

person1.show4()()
person1.show4().call(person2)
person1.show4.call(person2)()
结合 MDN 的文章,咱们一起来分析下这道面试题。

person1.show1():作为对象的方法,this 是调用该函数的对象,在这里即为 person1, 所以输出 person1

person1.show1.call(person2): 可以通过使用函数继承自 Function.prototype 的 call 或 apply 方法将 this 值绑定到调用中的特定对象,这里即为 person2,所以输出 person2

person1.show2(): 在箭头函数中 this 是它被创建时候的环境,(箭头函数不会创建自己的 this , 它只会从自己的作用域链的上一层继承 this),show2 的作用域链上一层即全局作用域,所以输出 window

person1.show2.call(person2): 使用箭头函数,如果将 this 传递给 call apply bind , 它将被忽略,所以与 person1.show2() 一致,输出 window


正如 相学长总结的,在我们学习的过程中,我们总是想以总结规律的方法去总结结论,并且希望结论越简单越容易描述就越好。实际上可能会错失真理。所以单一的仅靠 MDN 上分析的 this 使用场合分析不同场景是不够的。所以想弄懂这种情况,还得深度学习 箭头函数
于是我又转向看其他文章

OMG, 追根溯源的从 ECMASciript 规范讲解 this 的指向,嗯,成功得出结论,我真的不懂 this

退出移动版