Winchestro
Winchestro

Reputation: 2188

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.

Upvotes: 0

Views: 570

Answers (2)

Bergi
Bergi

Reputation: 664484

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

Upvotes: 1

alexpods
alexpods

Reputation: 48495

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

Upvotes: 1

Related Questions