33

I'm not sure if this is normal behavior, but running this:

for (var i in [1, 2, 3]) {
    console.log(i + 1);
}

Results in this:

// 01
// 11
// 21

Could somebody please explain, why is var i being treated like a string in this situation and not if I do for (var i = 0; i < [1, 2, 3].length; i++)?

5
  • 3
    If you are using a platform that supports a suitable subset of ES6, a for-of loop will give you the behavior you want: for (let i of [1, 2, 3]) { console.log(i + 1); } Commented Aug 17, 2016 at 6:50
  • 1
    for (var i of [1, 2, 3]) { console.log(typeof i); console.log(typeof (i + 1)); } for (let i of [1, 2, 3]) { console.log(typeof i); console.log(typeof (i + 1)); } Both are resulting in number type. But remember in js everything treated as object and key objects are usually strings. Commented Aug 17, 2016 at 8:28
  • 4
    Just when you think you've seen all the weird JavaScript behaviours, something like this comes up. Commented Aug 17, 2016 at 10:53
  • 1
    Why is using a for ... in loop for JavaScript arrays a bad idea? Commented Aug 17, 2016 at 12:33
  • Is JavaScript array index a string or an integer? Commented Aug 17, 2016 at 17:53

8 Answers 8

38

Its most likely because in this for loop style (for..in), it is treating i as a key, and since keys in objects are usually strings (yes, an array is a type of object in javascript), it is treating it as a String.

parseInt(i) works in this situation, but for good programming practice, you would want to use a for loop that looks similar to this:

var array = [1, 2, 3];
for (var i = array.length - 1; i >= 0; i--) {
    // do work with each array element here
} 
Sign up to request clarification or add additional context in comments.

7 Comments

Alternatively, if the code you've submitted is not just a boiled down example to illustrate a bigger issue, use the old fashioned for(var i = 0; i < 3; i++){}
While the end result is what the OP wanted, I would call this a bad programming practice.
You absolutely should not use parseInt here. Rather use a proper loop.
@You: Thanks, much better, though looping backwards is quite unidiomatic
@You It's not "better". You should favour readability over microoptimisations.
|
18

The reason is that for .. in iterates object properties ("keys"), even for arrays. The "keys" in this case are the "indexes" of the array but it's still just object keys. As all object keys are strings, i gets a string value.

Comments

12

I think you want the values of the array, not the keys. If you can't use ES6, Xorifelse's answer works, but if you can, there is for ... of that works exactly as you probably thought:

for (let i of [1, 2, 3]) {
  console.log(i + 1);
}

There is also Array.prototype.forEach in ES5 and up:

[1, 2, 3].forEach(function(value, index) {
  console.log(value + 1);
});

2 Comments

here you get the value, in the OP's code, they get the key.
Yes, that's what I wrote.
10

Using the in keyword you're looping over each key in the object and those are string types and when using the + operator on a string will cause it to do a concatenation assignment.

If you want to perform an arithmetic assignment both the left and the right value of the operator have to be an integer type. A solution would be to try to parse the string to an integer:

console.log(parseInt("0") + 1); // 1

However...
You should be looping over the value instead:

var data = [1, 2, 3];

for(var key in data){
  console.log('a: data['+ key + '] = ' + data[key]);
}

for (var i = 0; i < data.length; i++) {
  console.log('b: data['+ i + '] = ' + data[i]);
}

data.forEach(function(value, index){
  console.log('c: data[' + index + '] = ' + value);
});


You could use the ES6 method to loop over the value alone:

for(let v of [1, 2, 3]) {
  console.log(v);
}

The drawback of this method is the incompatibility of older android devices since its a somewhat new standard.


If you're using jQuery, you can also take a look at $.each as it allows for a key, value iteration in a nice one-liner that is compatible with older devices.

$.each([1, 2, 3], function(index, value) {
  console.log( index + ": " + value );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Comments

5

It's because i is a key/ index of every element, and it's string type. So you are in fact concatenating string and int – the result is string.

Comments

4

That is because with the "in" keyword you traverse the keys of the object, not array indexes. However in this case, since the object is an array, the keys of the items in are indexes. And last, the keys in a for..in loop are strings.

So if you need numeric indexes of an array, you need to use a regular for loop.

var array = [0, 1, 2];
for (var i = 0; i < array.length; i++) {
  console.log(i + 1);
}

Comments

3

Well when you use the for...in loop you're visiting each key from an object. Arrays are objects and their keys are numbers, but usually object keys are treated like strings.

If you want to convert the key to int, you can use parseInt function. link!

Comments

-5

for (var i in [1, 2, 3]) {
    console.log(parseInt(i) + parseInt(1));
}

1 Comment

No need to parse an existing integer type.. only i is a string.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.