jlewkovich
jlewkovich

Reputation: 2775

Wrong keys are printed using for..in on Object.keys()

Consider this object: var obj = {10: 0, 11: 1, 12: 2};

Using the method Object.keys(obj), you can see that obj has three keys: 10,11,12.

However, if you wanted to iterate over each key (for example, in order to get the value for each key), a standard for loop returns the correct keys, but the "for in" style does not. Does anyone know what's going on here? Is it possible to get the correct key names using "for in"?

JSFiddle: http://jsfiddle.net/n7sm22kb/

Upvotes: 2

Views: 2209

Answers (2)

Jim Thompson
Jim Thompson

Reputation: 41

I suspect @jlewkovich wanted to use

for (key of Object.keys(obj)) {

rather than:

for (key in Object,keys(obj)) {

Notice of rather than in. I say that because I found this page after making that mistake.

PS: I tried to add this as a comment, but don't have the reputation points, so please forgive a new answer where I think a comment would have been more appropriate. @ssube answered the question. This is an answer to a different question I think the author would have liked to ask.

Upvotes: 1

ssube
ssube

Reputation: 48327

In your specific example, this is because Object.keys returns an array. for ... in and Object.keys do very similar things, so you're iterating over the keys of the array of keys, hence your problem.

You can see this by running:

var obj = {10: 0, 11: 1, 12: 2};
var keys = Object.keys(obj); // ['10', '11', '12'];
for (var key in keys) {
  console.log('Keys has', keys[key], 'at', key);
}

The proper equivalent using for ... in would be more like:

for(var key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(obj[key]);
  }
}

You can see the additional complexity introduced here.

for ... in (#12.6.4 in the spec) loops over all enumerable properties in the object, including ones inherited from the prototype, causing it to include a lot of stuff you may need to filter out. In the case of an array, it loops over the property names (i.e., array indices) of each item in the array. This is the second level of indirection you're running into problems with.

Object.keys (#15.2.3.14 in the spec) is defined to only retrieve keys from the object itself ("For each own enumerable property..."), saving you the need for that check.

When possible, prefer Object.keys in most cases, as it saves you the logic. If [].forEach is available, you can also use that:

Object.keys(obj).forEach(function (key) {
  console.log('Object has', obj[key], 'at', key);
});

Upvotes: 4

Related Questions