nervosol
nervosol

Reputation: 1291

Strange behaviour of array in double for loops - JavaScript

I have rootObject which holds childObject as a value. I use two for loops to get values from childObject and put them to array. Array is cleared in every iteration of outer loop.

var childObject = new Object();
for (var i = 0; i < 3; ++i) {
    childObject[i] = i*i;
}

var  rootObject = new Object();
rootObject[0] = childObject;

I am using console.log(resultArray) to observe array. And this is what I got:

When clearing before second for loop

var resultArray = []
for ( var rootKey in rootObject){
    resultArray.length = 0; //clearing array
    for ( var childKey in rootObject[rootKey]){
       resultArray.push([ parseInt(childKey), rootObject[rootKey][childKey] ]);
    }
    console.log(resultArray);
}

I get [Array[2], Array[2], Array[2]

When clearing after second for loop

var resultArray = []
for ( var rootKey in rootObject){
    for ( var childKey in rootObject[rootKey]){
       resultArray.push([ parseInt(childKey), rootObject[rootKey][childKey] ]);
    }
    console.log(resultArray);
    resultArray.length = 0; //clearing array
}

I get []

Why result is different?

EDIT

I am using Firefox 29

http://jsfiddle.net/xf78k/5/ <-- good

http://jsfiddle.net/xf78k/6/ <-- bad

Upvotes: 0

Views: 127

Answers (2)

mlr
mlr

Reputation: 896

You store a reference to the array into your var, and print it through the console, that will show you the realtime (dynamic) state of the array. In other words, the console will show you three times the same objects, in both cases, and its state will be the final state of resultArray.

If you converted it to string, or printed its length, you'd have the expected result, because it would be a primitive value, and the console wouldn't keep track of its reference.

Taste the difference:

var childObject = new Object();
for (var i = 0; i < 3; ++i) {
    childObject[i] = i*i;
}

var  rootObject = new Object();
rootObject[0] = childObject;

var resultArray = []
for ( var rootKey in rootObject){
    for ( var childKey in rootObject[rootKey]){
       resultArray.push([ parseInt(childKey), rootObject[rootKey][childKey] ]);
    }
    console.log(resultArray.length);
    resultArray.length = 0; //clearing array
}

One suggestion: don't initialize plain objects with "new Object()".

var childObject = {};

is to be preferred instead.

EDIT: why you'd rather prefer the literal syntax to init objects

Try this code:

var a = new Object(1);
var b = new Object("1"); 

The result is that a is a Number(), and b is a String, because Object accept an optional parameter that drives which constructor is used for the object.

So, it is error prone.

Now try this:

Object = function () {
    //xmlhttp=new XMLHttpRequest("malicious site"); ...         
    console.log("XSS attack") 
} 
var c = new Object(); 

any script can override it, while {} is safer.

Finally, due to JS engines optimization, the literal syntax leads to better performance.

More

Upvotes: 4

ffflabs
ffflabs

Reputation: 17481

console.log does lazy and async evaluation of variables. Since arrays are passed by reference, it's not strange for it to reflex the value it has after clearance.

If you insert a breakpoint before clearing you should see the array with its elements.

Upvotes: 0

Related Questions