简体   繁体   中英

es6 class with default property on prototype throws in traceur

I recently started using traceur and stumbled upon an odd behavior when creating a class with default values on the prototype. I want to know if is this a bug in traceur or is this the intended behavior for 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

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. Also I'm unable to get that Error to throw in es5 on sealed/frozen/non-extensible objects and as far as I know Proxies aren't implemented in V8, so... how does it throw the error in the first place? It's not a compile-time error.

My main interest isn't to "make it work", which is trivial. All you need to do is replace this.v = v by the Object.defineProperty equivalent. I primarily want to know if and why it behaves this way and if there are negative performance implications in this data structure that outweigh the memory gain by assigning default properties to the prototype instead of storing them on every instance.

If you define property using Object.defineProperty specifying only value instead of get and set , then you are using data descriptor (see here ). With data descriptor you can add writable property to specify whether property can be changed or not. By default writable=false .

So if you're specifying only value of data descriptor, without writable: true - you can't change that property later. This behavior has nothing with ES6, as Object.defineProperty was introduced in ES5.

Correct code:

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.

Yes, the property is read-only as the writable attribute defaulted to false . And when the v property is inherited, this attribute is also in effect for assignments.

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

You just have to use strict mode and it'll do:

"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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM