I have noticed something that I cannot understand at all. I am doing something really simple in JavaScript:
var a = [1,2,3];
console.log(a.push(4));
console.log(a);
console.log(a.push(5));
I would expect the console to log: 4, [1,2,3,4], and 5 as described here for example.
The catch is that the actual console output looks like: 4, [1,2,3,4,5], and 5
See: http://jsfiddle.net/HknMF/
What on earth makes the 5 appear in the second log output?
EDIT: fwiw here's a screenshot of Firebug showing both behaviors: http://i.imgur.com/fwAK3.png
The console in some browsers uses a reference to the array/object, so when you inspect it and the object changed after the console.log() call you'll see the changed object.
In Firefox this also happens for objects, but not for arrays which are displayed inline anyway:
>>> var a = [1,2,3]; console.log(a.push(4)); console.log(a); console.log(a.push(5));
4
[1, 2, 3, 4]
5
Especially for objects that do not contain functions a quick workaround is either cloning them (log $.extend({}, yourObject) if you have jQuery) or logging their JSON string version (then you lose the nice object view and just get a plain string though). An array can easily cloned (shallow copy!) using a.slice(0)
Dependent of the Browser either your live array gets logged (Chrome) or A string representation (Firefox).
A shallow copy is sufficient to prevent that. Use:
console.log( a.slice(0) );
for that.
Related
I'm doing some small experiments based on this blog entry.
I am doing this research in Google Chrome's debugger and here comes the hard part.
I get the fact that I can't delete local variables (since they are not object attributes). I get that I can 'read out' all of the parameters passed to a function from the array called 'arguments'. I even get it that I can't delete and array's element, only achieve to have array[0] have a value of undefined.
Can somebody explain to me what undefined x 1 means on the embedded image?
And when I overwrite the function foo to return the arguments[0], then I get the usual and 'normal' undefined.
This is only an experiment, but seems interresting, does anybody know what undefined x 1 refers to?
That seems to be Chrome's new way of displaying uninitialized indexes in arrays (and array-like objects):
> Array(100)
[undefined × 100]
Which is certainly better than printing [undefined, undefined, undefined,...] or however it was before.
Although, if there is only one undefined value, they could drop the x 1.
Newer versions of Chrome use empty instead of undefined to make the difference a bit clearer.
For example, entering [,,undefined,,] in the DevTools console results in:
▼(4) [empty × 2, undefined, empty]
2: undefined
length: 4
▶__proto__: Array(0)
Google Chrome seems to choose to display sparse array using this undefined x n notation. It will show [undefined, undefined] if it is not a sparse array:
var arr = new Array(2);
console.log(arr);
var arr2 = [];
arr2[3] = 123;
console.log(arr2);
var arr3 = [,,,];
console.log(arr3)
var arr4 = [,];
console.log(arr4)
var arr5 = [undefined, undefined]
console.log(arr5)
var arr6 = [undefined]
console.log(arr6)
arr1 to arr4 are all sparse arrays, while arr5 and arr6 are not. Chrome will show them as:
[undefined × 2]
[undefined × 3, 123]
[undefined × 3]
[undefined × 1]
[undefined, undefined]
[undefined]
note the [undefined x 1] for the sparse array.
Since you deleted an element, it follows that: If you delete an element from an array, the array becomes sparse.
Here is how it looks, Type this code into chrome devtools console:-
arr = new Array(4);
arr[2] = "adf";
console.log(arr); // [undefined × 2, "adf", undefined × 1]
See the first two consecutive "undefined" that are represented by *2, to show that there are two consecutive undefined there
It just happened to me too. Open the same thing in another browser and output/log the array to the console. As long as it works in both crome and in firefox the same way (as in accessing the elements works fine even if the output has the undefinedx1), I consider it some kind of bug in Chrome not refreshing something internally. You can actually test it this way:
I was adding elements to an array, and firing console.log() to log the element, to check if it was undefined or not. They were all defined.
After push() I logged the array and it seemed that when this happened, it was always the last one being undefined x 1 on Chrome.
Then I tried logging it more times and also later, but with the same result.
However when I accessed (for the sake of output), the element by its index, it returned the proper value (funny).
After that I logged the array again and it said the last index was undefined x 1 (the very one I just accessed directly with success!).
Then I did a for loop on the array, logging or using each element, all showed up fine.
Then another log on the array, still buggy.
The code I'm originally using has checks for undefined and they didn't fire, but I was seeing all these undefineds in the console and it was bugging me (no pun intended).
Also worth reading: Unitialized variables in an array when using only Array.push? I'm using pop() too in my code and it's a reasonable explanation that the console log actually represents a different state in time (when the code is 'halted').
This question already has answers here:
console.log() async or sync?
(3 answers)
Closed 6 years ago.
In JavaScript, it appears if I define an array, print that array to the console, then change the array, then print to the console again, the two printings will appear different. Same for objects. This makes sense to me - the first time I print it, it hasn't changed yet, and the second time it has been changed.
However, through testing I've found that if I define an object within an array, print it, change the object, then print again, both printings will be the same (they will both be the changed version). Similarly if I define an array within an object, print it, change the array, then print it again, both printings will be the same (they will both be the changed version).
I think this may be related to passing by reference or by value? But I'm unclear how to relate that concept here. Some articles that I think may be related to my answer:
(SO) Is JavaScript a pass-by-reference or pass-by-value language?
(SO) Javascript by reference vs. by value
http://snook.ca/archives/javascript/javascript_pass
If anyone could help explain I would be very appreciative. Here are the tests I wrote to exemplify what discrepancy I'm asking about:
// Testing changing an array
// RESULT: Array console.logs are DIFFERENT before and after the change.
var arr123 = [1,2,3];
console.log(arr123);
arr123[0] = 4;
arr123[1] = 5;
arr123[2] = 6;
console.log(arr123);
// Testing changing an object
// RESULT: Object console.logs are DIFFERENT before and after the change.
var obj123 = {
first: 1,
second: 2,
third: 3
};
console.log(obj123);
obj123.first = 4;
obj123.second = 5;
obj123.third = 6;
console.log(obj123);
// Testing changing an object inside of an array.
// RESULT: Array console.logs are THE SAME before and after the change, reflecting the change.
var arrOfAnObj = [
{first: 1, second: 2, third: 3}
];
console.log(arrOfAnObj);
arrOfAnObj[0].first = 4;
arrOfAnObj[0].second = 5;
arrOfAnObj[0].third = 6;
console.log(arrOfAnObj);
// Testing changing an array inside of an object.
// RESULT: Object console.logs are THE SAME before and after the change, reflecting the change.
var objOfAnArr = {
arr: [1, 2, 3]
};
console.log(objOfAnArr);
objOfAnArr.arr[0] = 4;
objOfAnArr.arr[1] = 5;
objOfAnArr.arr[2] = 6;
console.log(objOfAnArr);
In all your cases you are modifying the initial object, it's just related to how and when the browser reads the object you passed it through console.log().
Explanation
I executed your code in this repl and the results are always different there.
I executed in chrome and I could reproduce you case. So it has to do with when the browser reads your variable. Because in the first two cases the variable has only one level so chrome shows you the values inline, and therefore reads the object at the point where it is logged.
In the last two cases you have one more level so chrome reads the object reference when you expand the object in the console.
Also I noticed that chrome displays your logs differently whether you run your code while the dev tools are open or when you run your code before opening the dev tools.
If you run the code before opening the dev tools you get the following output:
Whereas if you open the dev tools before running the code you get the following output:
I don't understand how to interpret this debug data. I do a console.log of my object, and on the summary-line that appears in the console I am shown windows: array[0] but if I expand the object, I am shown that windows is an array of 2 items.
Which is the correct one?
My code seem to run on the summary version, ie. windows array being empty.
Does anyone know what my problem is - why is the object presented in an inconsistent way?
The object is being mutated between when you print it and when you view it. When it's initially logged, it's empty but by the time you open it, 2 items have been added.
var obj = { arr: [] };
console.log(obj); // Will say { arr: Array[0] }
obj.arr.push(1); // Open it up in the console after this
Basically, the dev tools print a string that's representative of it's state at the time of the log but it stores a reference to the object in the console itself.
I'm running a splice on an array like this, where the array has 5 elements:
array.splice(3, 0, newObj);
The splice doesn't work and I still have 5 elements.
When I debug it in Chrome with console.log I see an array of six objects, but when I open the array I see five elements (see pic below). What does this mean?
You're inserting a new object into that array -> newObj
For example, if you run this in Chrome console, works fine :
function aHandler (){
var a = [{1:1},{1:2},{1:3},{1:4},{1:5}];
a.splice(3,0,{1:20});
console.log(a);
}; aHandler();
Even if you insert null or undefined console.log should show you the right object.
So, maybe you modify the object somewhere between splice and console.log
I have an array like:
errors = [ {...}, {...}, {...} ]
It's an instanceof array, yet it only returns 1 for .length?
Relevant code:
if(data.error){
errors.push({'element':ele,error:data.error});
}
//Above is looped a few times and there are N number of errors now inside
console.log(errors) //Returns 2+ objects like {...}, {...}
console.log(errors.length) //Returns 1
For Uzi and Muirbot, here's the errors array:
[
Object
element: b.fn.b.init[1]
error: "You must enter "example" into the field to pass"
__proto__: Object
,
Object
element: b.fn.b.init[1]
error: "Crap!"
__proto__: Object
It is correct, this code:
var errors = new Array();
errors.push({'element':'ele', error:'data.error'});
...adds ONE object to the array. The object has two properties.
It's possible your code is executing in an order other than what you're expecting. ie, when you log both errors and errors.length, errors does contain only 1 object. But after that you are adding to the errors array, and only after that are you looking at the console. At that point you could see a larger array in errors for two reasons - first, your actual code isn't logging errors but some object that contains errors. In that case the console display is live, and will show you not what was in errors at the time, but what is in it now. Alternatively, the console could just be taking some time to log errors.
Without more code I can't be sure if this is the case. But you could verify it by replacing console.log(errors); with console.log(errors[1]);. If errors is really only 1 long at the time, it will log undefined.
The problem was that Chrome's Web Inspector's console.log is an async event. So, the length was a property lookup so it gave that back instantly, but the object with two items inside was held off until the rest of the events had fired.
In the future I, and others with this issue, should use debugger; instead.
is it an Array object or something that resembles it?
arrays do work:
> a = [{a:1}, {b:2}]
[Object, Object]
> a.length
2
you'll have to provide more code.
and now that you've provided the relevant code, the correct answer is what Steve Wellens said (which was downvoted, by the way).
Array.push adds a single element, objects may have more than one key but they're still a single object so your real case was different from your original example, which of course works.
another possibility:
> a = []
[]
> a.length = 2
2
> a
[]
> a.length
2
> a instanceof Array
true