views:

108

answers:

2

I'll start with the code:

var s = ["hi"];
console.log(s);
s[0] = "bye";
console.log(s);

Simple, right? In response to this, Firebug says:

["hi"]
["bye"]

Wonderful, but Chrome's JavaScript console (7.0.517.41 beta) says:

["bye"]
["bye"]

Have I done something wrong, or is Chrome's JavaScript console being exceptionally lazy about evaluating my array?

+3  A: 

Thanks for the comment, tec. I was able to find an existing unconfirmed Webkit bug that explains this issue: https://bugs.webkit.org/show_bug.cgi?id=35801

There appears to be some debate regarding just how much of a bug it is and whether it's fixable. It does seem like bad behavior to me. It was especially troubling to me because, in Chrome at least, it occurs when the code resides in scripts that are executed immediately (before the page is loaded), even when the console is open, whenever the page is refreshed. Calling console.log when the console is not yet active only results in a reference to the object being queued, not the output the console will contain. Therefore, the array (or any object), will not be evaluated until the console is ready. It really is a case of lazy evaluation.

However, there is a simple way to avoid this in your code:

var s = ["hi"];
console.log(s.toString());
s[0] = "bye";
console.log(s.toString());

By calling toString, you create a representation in memory that will not be altered by following statements, which the console will read when it is ready. The console output is slightly different from passing the object directly, but it seems acceptable:

hi
bye
Eric Mickelsen
Actually, with associative arrays or other objects, this could be a real problem, since toString doesn't produce anything of value. Is there an easy work-around for objects in general?
Eric Mickelsen
A: 

Looks like Chrome is replacing in its "pre compile" phase any instance of "s" with pointer to the actual array.

One way around is by cloning the array, logging fresh copy instead:

var s = ["hi"];
console.log(CloneArray(s));
s[0] = "bye";
console.log(CloneArray(s));

function CloneArray(array)
{
    var clone = new Array();
    for (var i = 0; i < array.length; i++)
        clone[clone.length] = array[i];
    return clone;
}
Shadow Wizard
That's good, but because it's a shallow copy, there is still the possibility of a more subtle problem. And what about objects that aren't arrays? (Those are the real problem now.) I don't think that what you're saying about "pre compile" is accurate. Also, there is an error in the code: clone[clone.length] should be clone[i].
Eric Mickelsen