3

I was reading though Javascript, the definitive guide and came across a paragraph which said and I quote

If you index an array with a string that happens to be a non-negative integer,it behaves as an array index not an object property

So something like a["4"] would be stored at an index of 5, whereas something like a["-1.26"] would be stored as a property "1.26"..

I got a little adventurous and tried a["02"] = 2; Now I can set it, retrieve it but it's neither set as a[2] (basically a[parseInt("02")]) , nor can I get it when I print the array ..

Here is my code. I tried it with node and the browser.

> a[3] = 3;
3
> a["-1.2"] = 10;
10
> a
[ , , , 3, '-1.2': 10 ]
> a["02"] = 2;
2
> a
[ , , , 3, '-1.2': 10 ]
> a["02"]
2
> a.length
4

I just want to understand what exactly is happening.

4
  • When the index isn't a number, the array rolls back to using Object properties. Commented Aug 11, 2013 at 17:32
  • Not a good idea to mix array-style access with object-style access, because the exact behaviour varies (e.g. sorting order), but essentially numeral keys get some special treatment Commented Aug 11, 2013 at 17:34
  • I think that what you're seeing may just be an artifact of the way your JavaScript console works when dumping out the contents of an array. There's really no difference between "02" and "-1.2" as property names; neither will count as an array index. Commented Aug 11, 2013 at 17:37
  • I'll say that everything that is /^0|[1-9][0-9]*$/ is treated as a number. a["+1"] isn't a[1] Commented Aug 11, 2013 at 17:39

3 Answers 3

3

From specs

A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 2^32-1.

So the book is misleading, as it needs to be exactly an integer, no leading zeroes etc.

So "02" is treated like "hellokitty" - not an indexed property in any sense.

Consider :

var P = "02"
console.log( ( P ) === ( ( +P >>> 0 ).toString() ) );
//false

var P = "2"
console.log( ( P ) === ( ( +P >>> 0 ).toString() ) );
//true

Here's a function

function isStringConsideredArrayIndex( P ) {
    if( typeof P !== "string" ) throw new Error( "strings only" );
    return ( (P >>> 0).toString() ) === P && 
        ( P >>> 0 ) !== ( Math.pow( 2, 32 ) - 1 );
}
Sign up to request clarification or add additional context in comments.

4 Comments

Great ! That explains why it's not being stored as an index, but why can I not see it as a property like I see "-1.2", when I can retrieve it as one.
@akanksha1105 what? The console.log output is not specced anywhere. You should not trust it in this sense at all. See console.log({splice: function(){}, length: 100, 50: 3}) or something
@Esailija akanksha1105 wants to know why console.log(a) isn't listing the key -1.2. edit: nevermind, you edited your comment.
@akanksha1105 to see all properties in somewhat sane format, try console.dir(array). If your question is about idiosyncrasies of console.log (which can do whatever random things it wants) then you should specify that --- not ask how names and indices are differentiated which is well defined issue and answered.
1

The main thing to know is that your "array" is actually more of a map (with some exceptions);

a = {}; // a is an empty object
a['02'] = 'foo';
a['2'] = 'bar';
console.log( a ); // { '02': 'foo', '2': 'bar' }

The same applies if a is an array, except that the way it's being printed may be different. For example, Google Chrome will only print the array-like keys of an array object (so in this case you would see [undefined, undefined, 'bar']. It still has the other properties, but its "printing function" for want of a better term is only displaying the array-like ones.

And there are other differences. Arrays have certain properties, such as length (which will be equal to the largest numeric index which you have defined + 1), and various manipulation functions ('pop', 'join', etc.).

As has been pointed out, an index is considered number-like if it can be converted to an unsigned integer losslessly. i.e. "2" -> 2 -> "2" loses nothing, whereas "02" -> 2 -> "2" loses the leading 0.

To see a full list of everything which is in an object or array, you can use this (which will show your missing "02" key):

for(var i in a){
    console.log(i,a[i])
}

4 Comments

Try with a = {splice: function(){}, length: 100}; in the first line :P
I agree, but my concern is two fold, one if it's storing it as a property, why don't i see it like I can see "-1.2" which is also a property, also if javascript is trying to convert the string to an int using the function ToUint32(As mentioned by Awake Zoldiek) , then > "02" >>> 0 // result is 2, so it should actually store it at index 2.
converting to ints only applies if it can convert losslessly. i.e. 02 -> 2, but 2 !-> 02, so it doesn't apply. Esailija's code is interesting. It's a subtlety I wasn't aware of, which I assume must relate to how the thing is printed.
@akanksha1105 as for your other concern, try this code: for(var i in a){console.log(i,a[i])} and you will see that all your properties are indeed present
0

Iternally, JavaScript will run the following function on array indexes before they are set :

    function ToUint32(x) {
        return x >>> 0;
    }

So, only numbers or strings that are numbers are valid Array indexes.

Indexes also have to be in the following range [0, 2^32−1].

If one a string isn't a number, it defaults back to object keys.

1 Comment

This is incorrect, and even half the confusion in the question. This would return 2 for "02" but the spec is pretty clear on the fact that leading zeroes in a numeric string disqualify it from being an array index

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.