es6 class 原型上的默认值 属性 在 traceur 中抛出

es6 class with default property on prototype throws in traceur

我最近开始使用 traceur 并在原型上创建具有默认值的 class 时偶然发现了一个奇怪的行为。我想知道这是 traceur 中的错误还是 ES6 的预期行为 classes?

class hasDefault {
  setValue ( v ) {
    this.v = v;
  }
}
Object.defineProperty( hasDefault.prototype, "v", {
  value : 5,
  enumerable : true
});

let a = new hasDefault;
console.assert(a.v === 5);
a.setValue(2);
console.assert(a.v === 2);

run in traceur REPL

它抛出一个错误,当我尝试设置它时,我无法将其分配给只读 属性 "v"。这没有意义,因为 属性 是在原型而不是实例上定义的。此外,我无法在 sealed/frozen/non-extensible 对象上将 es5 中的错误抛出,据我所知,代理未在 V8 中实现,所以......它首先是如何抛出错误的?这不是编译时错误。

我的主要兴趣不是 "make it work",那是微不足道的。您需要做的就是将 this.v = v 替换为 Object.defineProperty 等价物。我主要想知道它是否以及为什么会以这种方式运行,以及此数据结构中是否存在负面性能影响,通过将默认属性分配给原型而不是将它们存储在每个实例上来超过内存​​增益。

如果您使用 Object.defineProperty 定义 属性,仅指定 value 而不是 getset,则您使用的是 data descriptor(参见 here)。使用 data descriptor 可以添加 writable 属性 来指定 属性 是否可以更改。默认 writable=false

因此,如果您仅指定 value 数据描述符,而没有指定 writable: true - 您以后无法更改 属性。此行为与 ES6 无关,因为 Object.defineProperty 是在 ES5 中引入的。

正确代码:

class hasDefault {
  setValue ( v ) {
    this.v = v;
  }
}
Object.defineProperty( hasDefault.prototype, "v", {
  value : 5,
  writable: true,
  enumerable : true
});

let a = new hasDefault;
console.assert(a.v === 5);
a.setValue(2);
console.assert(a.v === 2);

Traceur REPL

It throws an error that I can't assign to the read only property "v" when I try to set it. Which doesn't make sense as the property is defined on the prototype, not the instance.

是的,属性 是只读的,因为 writable 属性默认为 false。而当v属性被继承时,这个属性对赋值也是有效的。

Also I'm unable to get that Error to throw in es5

您只需使用严格模式即可:

"use strict";
var test = Object.create(Object.defineProperty({}, "v", {value: 5, enumerable: true}));
console.log(test.v) // 5
test.v = 1; // Unhandled Error: Invalid assignment in strict mode