for own(...) loop (spin-off from Re: for..in, hasOwnProperty(), and inheritance)

Brendan Eich brendan at mozilla.com
Tue Nov 8 14:50:55 PST 2011


On Nov 8, 2011, at 2:03 PM, Quildreen Motta wrote:

> On 08/11/11 18:49, Brendan Eich wrote:
>> 
>> The recommended practice when writing for-in loops in JS today is to write:
>> 
>>   for (i in o) {
>>     if (o.hasOwnProperty(i)) {
>>       body
>>     }
>>   }
>> 
>> Although many JS developers do not follow the recommendation (out of ignorance or intentionally, doesn't matter).
>> 
>> Should ES.next provide sugar for the recommended pattern? To make it compose with declarations and destructuring in the for head, it should use a contextual keyword immediately after 'for':
>> 
>>   for own (i in o) {
>>     body
>>   }
>> 
>> This is a small thing but it might pay off in the long run.
> Isn't that just:
> 
> Object.keys(o).forEach(function(i){ body })

Good grief. Your "just" is pointing the wrong way. The longer, more contingent in terms of mutable global and Object property bindings, form is not the primitive one.


> Iirc, that's faster than a for..in loop with filter in v8 due to the aggressive function inlining, not sure about SpiderMonkey.

It's not necessarily faster or slower, implementations vary. And what is the length of the necessarily-reified, returned keys array? Have you tested large objects?

You can use it if you like (performance is not usually overriding).


> It also reads better and it's more composable -- for me, at least.

YMMV.

Again, ES.next already will support

  for (let i in keys(o)) {
    body
  }

if you have keys imported. There is no "there must be only one way to say things in JS" dogma in JS; this is a feature.


> I do use keep `var keys = Object.keys' and other hand aliases though.
> 
> It still seems to me it's overkill to add special syntax (and a new reserved word, yuck!)

No new unconditionally reserved word. Rather, contextually reserved after 'for', no impact on other uses of 'own'. ECMA-357 (E4X) did likewise with 'for each(... in ...)'.

Overkill may be writing a function around one's code just to call an array extra on a reified array of keys. Iterators can be much faster.

Here's another, more real-world concern: wrapping //body// in function (){...} breaks the principle of equivalence (TCP) and people can and do fail to capture the outer |this|, e.g. by var self = this, and propagate it to the revised //body// as self. Tom Van Cutsem had such a bug, Mark Miller has seen such bugs. They are serious runtime type/instance confusion bugs, possibly with security implications.

(Block-lambdas would help here, shameless plug -- but let's stay on target.)


> to something that isn't really worth it, given the Object API already provides those methods.

for-in loops are quite commonly used. Object.keys is new and while people polyfill it, practice varies wildly.


> Also, are Object.values and Object.items standardised in ES.next. They're quite useful?

They are *not* object methods, and you're mistaking Object.keys for the "@iter" module's keys function.

Returning iterators instead of eager arrays is a serious perf win for large objects.

/be


> 
>> 
>> /be
>> 
>> 
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
> 
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111108/5b1a09b8/attachment.html>


More information about the es-discuss mailing list