0

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

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);

在 traceur REPL 中运行

当我尝试设置它时,它会引发我无法分配给只读属性“v”的错误。这没有意义,因为属性是在原型上定义的,而不是在实例上。此外,我无法在密封/冻结/不可扩展的对象上抛出 es5 的错误,据我所知,代理没有在 V8 中实现,所以......它是如何首先抛出错误的? 这不是编译时错误。

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

4

2 回答 2

1

如果您使用Object.defineProperty仅指定value而不是getand来定义属性set,那么您正在使用data descriptor(参见此处)。data descriptor您可以添加属性以writable指定是否可以更改属性。默认情况下writable=false

因此,如果您仅指定value数据描述符,writable: true则 - 您以后无法更改该属性。Object.defineProperty正如ES5 中引入的那样,这种行为与 ES6 无关。

正确代码:

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

于 2015-02-08T13:05:29.323 回答
1

当我尝试设置它时,它会引发我无法分配给只读属性“v”的错误。这没有意义,因为属性是在原型上定义的,而不是在实例上。

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

我也无法在 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
于 2015-02-08T13:20:49.947 回答