2

How can I access the counter of a for..in loop?

I have an array and an object. I want to iterate over the object properties while doing the same with the array, without explicitly declaring a counter.

var colors = ['red','yellow','purple','blue'];

var flowers = {'rose':'','sunflower':'','violet':'','hydrangea':''};

for (prop in flowers) {
    flowers[prop] = colors[i];
}

Follow up question. If not possible, how would I create my own for loop with the functionality I require. Here's how it's working currently but I find I'm doing this often and want to create something reusable.

var colors = ['red','yellow','purple','blue'];

var flowers = {'rose':'','sunflower':'','violet':'','hydrangea':''};

var i = 0;
for (prop in flowers) {
    flowers[prop] = colors[i];
    i++;
}
6
  • @DanielA.White I've reworded the question. Commented Jun 1, 2014 at 15:54
  • do you just need the index of the property? because that really doesn't exist Commented Jun 1, 2014 at 15:55
  • yes, why have you down voted my question? Commented Jun 1, 2014 at 15:56
  • 1
    @T.J.Crowder True, assumptions do tend to make a... you know. noted. Commented Jun 1, 2014 at 15:59
  • 1
    @toddsby xkcd.com/1339 Commented Jun 1, 2014 at 16:02

1 Answer 1

4

(ECMAScript 2015 changes things, see update at end of answer.)

I have an array and an object. I want to iterate over the object properties while doing the same with the array, without explicitly declaring a counter.

I don't believe you can. Moreover, it's important to understand the that properties in the object have no order. You seem to be assuming you'll get "rose", then "sunflower", etc. That is simply not guaranteed. Many engines visit object property names in the order in which the properties were added to the object, and the order in which literal properties in an object initializer are added to the object is now (as of ES5 a couple of years back) specified, but visiting them in any particular order in for-in is not specified behavior (similarly, Object.keys is not sorted in any particular way), and a perfectly correct engine can visit them in any order it wants.

As such, with just the array and object you've shown, you have no reliable way to map those properties to the array entries.


As of ECMAScript 2015 (ES6), object properties have order now:

  1. Let keys be a new empty List.
  2. For each own property key P of O that is an integer index, in ascending numeric index order
    • Add P as the last element of keys.
  3. For each own property key P of O that is a String but is not an integer index, in property creation order
    • Add P as the last element of keys.
  4. For each own property key P of O that is a Symbol, in property creation order
    • Add P as the last element of keys.
  5. Return keys.

Okay, so we know that they'll be visited in "creation" order, but in what order are they created by an object initializer? Good news: Object initializers are processed in source code order, so that's deterministic. Your rose comes before your sunflower, etc.

This means that while you still can't do what you want without explicitly declaring and maintaining an index variable, you can relate that array and that object reliably:

// Works as of ES6
var colors = ['red','yellow','purple','blue'];

var flowers = {'rose':'','sunflower':'','violet':'','hydrangea':''};

let i = 0;
for (prop in flowers) {
    flowers[prop] = colors[i++];
}

I'm not suggesting doing it, but it's possible now, on compliant engines.

Sign up to request clarification or add additional context in comments.

6 Comments

internally doesn't a for in loop use an iterator, or is that also a poor assumption? My thoughts were if the loop was using an iterator I could access it from inside the for loop.
@toddsby: The current spec just says the engine should make a list and the loop doing the "next" property until done, without specifying the mechanics of that. The ES6 draft defines the algorithm in terms of iterators, but again the properties still have no order (er, unless they've added that somewhere), so even if ES6 defines it in terms of iterators, and even if it gave you access to the iterator, you still can't assume the first property you visit will be "rose".
How would I create a for loop with the functionality I require? (see updated question)
@toddsby: As I said above: You can't. The flowers object has no order, and so it's impossible to relate the properties of the flowers object by position. (Side note: I checked, and the April '14 ES6 draft says clearly in §9.1.11 that there is still no order to the properties, so they haven't slipped that into ES6 when I wasn't looking. :-) There's a May draft I don't have time to download and check right now, but I doubt they've changed that.)
Thank you for pointing me in the right direction. I wasn't grasping the difference between enumeration and iteration in how javascript handles a for in loop. I also found a possible solution here: How to keep Javascript object/array ordered while also maintaining key lookups
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.