Why Can Es6 Symbol Properties Be Made Enumerable By Object.defineproperty?
Solution 1:
Yes, there's a reason for allowing Symbol
properties to be enumerable: Object.assign
:
let s1 = Symbol();
let s2 = Symbol();
let s3 = Symbol();
let original = {};
original[s1] = "value1"; // EnumerableObject.defineProperty(original, s2, { // Enumerableenumerable: true,
value: "value2"
});
Object.defineProperty(original, s3, { // Non-enumerablevalue: "value3"
});
let copy = {};
Object.assign(copy, original);
console.log("copy[s1] is " + copy[s1]); // value1, because it was enumerableconsole.log("copy[s2] is " + copy[s2]); // value2, because it was enumerableconsole.log("copy[s3] is " + copy[s3]); // undefined, because it wasn't enumerable
Live Copy on Babel's REPL.
Just for clarity:
MDN defines enumerable properties as 'those which can be iterated by a for..in loop' (1).
That's simply wrong for ES6 (ES2015). It was a reasonable, if simplistic, definition in ES5 and earlier, no it's no longer even simplistically correct because of Symbol
s. I've fixed the article.
This is a CW because it was the outgrowth of the comments on the question.
Solution 2:
This is because the rules for enumeration include a clause requiring string keys. Bear in mind that enumeration and asking for keys are different operations with entirely different rules.
Looking at the section for for ... in
/for ... of
head evaluation (13.7.5.12), it states that the iteration is done using:
If iterationKind is enumerate, then
c. Return
obj.[[Enumerate]]()
.
The description of [[Enumerate]]
(9.1.11) very clearly states that it:
Return an Iterator object (25.1.1.2) whose
next
method iterates over all the String-valued keys of enumerable properties ofO
.
The check for enumerable properties comes later in the body, and the pseudo-code example makes this even more clear:
function* enumerate(obj) {
let visited=newSet;
for (let key ofReflect.ownKeys(obj)) {
if (typeof key === "string") { // type check happens firstlet desc = Reflect.getOwnPropertyDescriptor(obj,key);
if (desc) {
visited.add(key);
if (desc.enumerable) yield key; // enumerable check later
}
}
}
...
}
(comments mine)
Clearly, properties with non-string keys will not be enumerated. Using this example:
var symbol = Symbol();
varobject = {};
Object.defineProperty(object, symbol, {
value: 'value',
enumerable: true
});
Object.defineProperty(object, 'foo', {
value: 'bar',
enumerable: true
});
Object.defineProperty(object, 'bar', {
value: 'baz',
enumerable: false
});
Object.defineProperty(object, () => {}, {
value: 'bin',
enumerable: true
});
for (let f inobject) {
console.log(f, '=', object[f]);
}
for (let k ofObject.getOwnPropertyNames(object)) {
console.log(k);
}
you can verify that in Babel and Traceur.
However, you'll see two interesting things:
getOwnPropertyNames
includes non-enumerable properties. This makes sense, as it follows completely different rules.for...in
includes non-string properties under both transpilers. This does not seem to match the spec, but does match ES5's behavior.
Post a Comment for "Why Can Es6 Symbol Properties Be Made Enumerable By Object.defineproperty?"