直奔主题,给出如下代码:
class A { x = 1;}class B extends A { get x() { return 2; } set x(v) {}}const a = new A();const b = new B();console.log(a.x);console.log(b.x);
猜猜它们分别打印什么?
下面的代码呢:
class A { constructor() { this.x = 1; }}class B extends A { get x() { return 2; } set x(v) {}}const a = new A();const b = new B();console.log(a.x);console.log(b.x);
再下面的代码呢:
class A { x = 1; get x() { return 2; } set x(v) {}}const a = new A();
console.log(a.x);
你猜对了吗?
对于 public field
,我们观察它在 chrome devtools 下的展现:

可以看到 x
是 A
对象的实例变量,不在其 prototype
上。
而对于 x accessor
:

x accessor
出现在了 A
对象实例的 Prototype
上。
所以可作出如下结论:
Fields are part of the instance object. Accessors are part of the object's prototype.(fields 是对象实例的一部分,而 accessors 是对象原型的一部分。)
进而得出:
So fields are hit before methods/accessors. (fields 总是比 methods/accessors 先被访问。)
所以上面的几个问题,答案就容易推导了。
对于第一个问题,因为 x=1
作用于对象实例,而 get x
作用于对象 prototype,因此 x=1
先被访问,两个打印的都是 1
。
对于第二个问题,a.x
是 1
,而 b.x
是 2
。比较迷惑的是为什么 b.x
是 2
,因为在 contructor
方法里,this
指向的是构造完的对象,即 B
的实例,此时的 this
的 prototype 中有个 x accessor
,因此当调用 this.x=1
时,实际上是调用了 set x(v){}
这个accessor(如果不信,可以在 set x(){}
中加一句 console.log
观察)。由于该 set x
是空方法,因此 get x
会一直返回 2
。
对于第三个问题,和第一个问题一样,x=1
优先于 get x
被访问,故打印 1
。
(文章参考自一则推文讨论 https://twitter.com/davidmarkclem/status/1430914451268677635)




