Where in spec does it explain why setting the value of an existing property will change its [[Enumerable]] attribute.

# John-David Dalton (14 years ago)

So @kitcambridge and I were talking spec and started trying to find in spec something that explains why something like:

Array.prototype.reduce which is by default { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true } will change to [[Enumerable]]: true when:

Array.prototype.reduce = function() {…};

So far we have struck out. In ES3 we found 8.6.2.2 [[Put]](P, V) bclary.com/2004/11/07/#a-8.6.2.2 and its step 4: 4. Set the value of the property to V. The attributes of the property are not changed.

And then we dug into ES5.1 and its [[Put]] es5.github.com/#x8.12.5 and its step step 3a which leads to [[DefineOwnProperty]] with a Desc of {[[Value]]: V} and its step 10b to 12, then 13.

but couldn't find where it stated changing the [[Enumerable]] attribute.

Would you all help point to where this is defined in spec?

Thanks, JDD

# Allen Wirfs-Brock (14 years ago)

On Aug 16, 2011, at 9:44 PM, John-David Dalton wrote:

So @kitcambridge and I were talking spec and started trying to find in spec something that explains why something like:

Array.prototype.reduce which is by default { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true } will change to [[Enumerable]]: true when:

Array.prototype.reduce = function() {…};

Why do you think this should change [[Enmerable]] to true??

So far we have struck out. In ES3 we found 8.6.2.2 [[Put]](P, V) bclary.com/2004/11/07/#a-8.6.2.2 and its step 4: 4. Set the value of the property to V. The attributes of the property are not changed.

And then we dug into ES5.1 and its [[Put]] es5.github.com/#x8.12.5 and its step step 3a which leads to [[DefineOwnProperty]] with a Desc of {[[Value]]: V} and its step 10b to 12, then 13.

but couldn't find where it stated changing the [[Enumerable]] attribute.

Would you all help point to where this is defined in spec?

It isn't. Simply assigning a new value to an already existing own data property isn't supposed to change any attributes.

# Dmitry A. Soshnikov (14 years ago)

It shouldn't, even in ES3 (read attentively).

Dmitry.

# John-David Dalton (14 years ago)

Array.prototype.reduce which is by default  { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true } will change to [[Enumerable]]: true when:

Array.prototype.reduce = function() {…};

Why do you think this should change [[Enmerable]] to true??

Oh, I didn't say I think it should. I said we were trying to explain an existing behavior we were seeing.

Would you all help point to where this is defined in spec?

It isn't.  Simply assigning a new value to an already existing own data property isn't supposed to change any attributes.

Awesome! That was our conclusion too. It was late Kit and I missed trying it in other implementations (instead we dug into spec because we thought it was odd). It turns out V8 (Chrome, Node.js) has a bug that will make non-enumerable properties enumerable by assigning a new value as in my previous snippet :O

Thanks again, JDD

# Oliver Hunt (14 years ago)

On Aug 17, 2011, at 6:52 AM, John-David Dalton wrote:

Awesome! That was our conclusion too. It was late Kit and I missed trying it in other implementations (instead we dug into spec because we thought it was odd). It turns out V8 (Chrome, Node.js) has a bug that will make non-enumerable properties enumerable by assigning a new value as in my previous snippet :O

I suspect that this only applies to builtin properties on objects, as I think JSC has a similar issue.

Speaking for JSC (but i wouldn't be surprised if V8 did something similar) we will delay the creation of the majority of builtin properties until they're actually used, eg. until you actually access Array.prototype.reduce we won't reify the property. A side effect of this is that when you simply assign to the property we skip reification, and so the property attributes are the same as you would get if you were creating a new property.

A simple test would be to see if Array.prototype.reduce; Array.prototype.reduce = ...

Results in the correct behaviour.

# John-David Dalton (14 years ago)

Awesome! That was our conclusion too. It was late Kit and I missed trying it in other implementations (instead we dug into spec because we thought it was odd). It turns out V8 (Chrome, Node.js) has a bug that will make non-enumerable properties enumerable by assigning a new value as in my previous snippet :O

I suspect that this only applies to builtin properties on objects, as I think JSC has a similar issue.

You are right. V8 doesn't have this problem for object properties created with Object.defineProperty and friends. Also right again, JSC does appear to have a similar issue (tested Safari 2.0.0 - WebKit Nightly)

Speaking for JSC (but i wouldn't be surprised if V8 did something similar) we will delay the creation of the majority of builtin properties until they're actually used, eg. until you actually access Array.prototype.reduce we won't reify the property.  A side effect of this is that when you simply assign to the property we skip reification, and so the property attributes are the same as you would get if you were creating a new property. A simple test would be to see if Array.prototype.reduce; Array.prototype.reduce = ... Results in the correct behaviour.

Though it does avoid the bug in JSC, accessing the property before setting it doesn't affect V8 on built-ins as it will still bug.

I have made a simple test file here: dl.dropbox.com/u/513327/enum_bug.html

Another odd thing is that V8 uses the Array#push internally for Object.defineProperties. I noticed that if I set Array.prototype.push = 1; using Object.defineProperties(…) would error complaining about push not being a function.

# Andreas Rossberg (14 years ago)

On 17 August 2011 21:24, John-David Dalton <john.david.dalton at gmail.com> wrote:

Another odd thing is that V8 uses the Array#push internally for Object.defineProperties. I noticed that if I set Array.prototype.push = 1; using Object.defineProperties(…) would error complaining about push not being a function.

Yes, there are still several bugs like that in the V8 built-ins. The reason is that most of these built-ins are written in JS itself, and in some places the code isn't careful enough about applying the original function instead of just invoking an object method.