本人的一个小读后感,读后感原文在博客链接,博客欢迎添加友链
ECMAScript 规范 链接 https://v8.dev/blog/tags/understanding-ecmascript
水平有限,欢迎指点批评
ECMAScript 规范 这一合集,第一章主要讲了规范中的一些基础语法,注意,这里是规范的语法,
类似于 ! 和 ?,问号比较常用,它的作用类似于解除包装后的值,这一语法挺像 rust 的 Some 去匹配 Option 。
介绍完基本语法,第二章讲了非常实用的一个 js 操作,就是取值。
obj.foo 这个操作经历了什么,文章中是从底向上描述的。
如果是从顶向底描述,则是,obj.foo 这一个字符串先被词法分析器解析,解析之后,获得一个 Reference 对象,这个对象中包含了基值 obj 和键值 foo ,之后就会传给GetValue
GetValue
是一个规范内部的方法,接受一个参数 V ,这个参数的类型是一个 Reference ,Reference 中就包含了基值和键值,读这个方法,可以了解 js 的一些基本执行原理,下面是我自己对这个方法的描述;
如果 V 不是 Reference 类型,就直接返回 V ,
获取 Reference 中的 Base ,即基值,然后判断基值是否为原始类型,就是 number ,string 这些,如果是的话,就得把这些类型转为包装类型再调用其方法。如果不是原始类型,就调用`[[Get]]`方法,这个方法需要传入 V 的键值名字,还有一个 Receiver ,
Receiver 是通过 GetThisValue(V)获取的,这里的 GetThisValue ,其实相当于获取 V 的 Base ,基值。
[[Get]]
本身也是一个方法,
而[[Get]](P ,Receiver)
里面直接调用了?OrdinaryGet(O ,P ,Receiver),所以,直接看看 OrdinaryGet 的实现
OrdinaryGet 中详细定义了取值的规范。
下面我就把重要的过程描述一下:
取 obj 中的 foo 的值的时候,首先看对象本身有没有这个键值,如果没有,就调用 GetPrototypeOf 得到对象的原型,然后再调用原型的`[[Get]](P ,Receiver)`,这里就会产生递归,就会沿着原型链递归的查找键值。
那如果对象本身有这个键值呢?那就直接返回就好了,这里要判断一下,是能直接取到值,还是被 getter 函数包装了,如果被 getter 函数包装了,就再调用一下 getter 函数,然后返回值。这里规范内部调用 getter 的时候,还需要传 Receiver
上面的过程,可以明显看出,整个调用过程的 Receiver 就没变过!
还可以注意到,Receiver 一直传,一直传,传到了哪里?有什么用?
用一个例子来解释下。
看下面的代码:
const o1 = { x: 10, get foo() { return this.x; } };
const o2 = { x: 50 };
Object.setPrototypeOf(o2, o1);
o2.foo;
// → 50
调用 o2.foo 的时候,就找到了一个 o1 的 getter 函数,这里重要了,因为调用的是 getter ,所以调用 getter 方法,
getter 方法传入的 Receiver 就是 o2 ,进入到函数中,再使用 this 时,这里的 this 就是指的 Receiver o2 ,因为上面所说,Receiver 就没变过。
所以,直接得出 o2.foo 的值就是 50 ,而不是 o1 中的 10 。
从这个例子可以看出,规范中的一些定义,可以帮我们理清一些 js 怪异的行为,还是比较有帮助的。
怎么去阅读规范,那就是直接打开网页 https://tc39.es/ecma262/
1
chnwillliu 259 天前 via Android
搭配 super 食用效果更佳,还有 super.xxx = 5 这种左值用法😂
|
2
royalknight OP @chnwillliu 这一点还没看到
|