JavaScript: Can't access array in object - javascript

I'm experiencing extremely strange behavior when accessing a property of an object.
Running this code:
console.log(myObj);
console.log(myObj.items);
console.log(myObj);
I get this output in the console:
How could this possibly happen?

console.log, during execution, outputs a string representation of the value in the console. Depending on Chrome's mood, it might show something [object Object] or something like Object {}. That doesn't matter.
Now note the little blue i beside it. What it means is that the object has been modified between the time it was logged and the time you expanded it in the console, and it now shows the current value (with the 2 items), not the value during console.log's execution (no items). You can actually hover on the blue i to get the explanation.
To replicate the issue, open the console and run this snippet:
var obj = {arr: []};
console.log(obj);
console.log(obj.arr);
console.log(obj);
// by this time, you see 2 object logs, 1 empty array
// (representation differs from time to time)
// > Object
// []
// > Object
obj.arr.push(1,2);
// when you try to expand the objects, an array of 2 items magically appear
// but you still see the empty array ([]) in the log.
This behavior differs across browsers. As far as I remember, Firebug outputs a serialized version when console.log executes, hence this doesn't happen there.
Debugging the code
To debug this kind of code, you have several options:
The quickest way is to log the stringified version of the object using JSON.stringify, like console.log(JSON.stringify(obj));
The best way is to add a breakpoint via the Sources tab. Browse to your file in the Sources tab of the Dev Tools, and add a breakpoint in that position. Run your code, and it will pause at that point. Use the Scope panel to inspect the variables.
If you can't reach the code using a breakpoint (probably run using eval or injected in the console), you can use the debugger; statement. Just put it in the code at that position. Run the code and it will pause when it reaches the statement. Use the Scope panel in Sources tab to inspect.

You could look at the JSON representation of the object to check, you can do that with:
console.log(JSON.stringify(myObj, null, 2));

With so little information, I can only assume you're dynamically populating the items property, making it empty when the 2nd console log runs.
Now you're wondering why it is there in the 1st console log: the console doesn't show the object properties that were there at the time the object was logged, but rather at the time the object entry was expanded in the console, so it could be that the items were populated after your 2nd console log and before you expanded the 1st one. Try logging the object as a string or a JSON to see its actual state at the time the console log was run.
Bottom line: object properties in the dev console get updated only when you expand the object entry (when you click the arrow) so you're not seeing the actual representation of the object from the time it was logged.
Here's a simple demonstration - see how it can even turn from an array into a string:
var obj = {p: []}
console.log(obj);
setTimeout(function(){
obj.p = "I'm not even an array!";
}, 1000);

Related

Why the JSON's are different in Javascript?

I have written some code and I am printing to console . A very strange thing is happening .Below the screenshot attached :
There are two screenshot attached and in both the screenshots the attribute canvasWidth is showing some strange values. When it is unexpanded it is showing 287(expected) and when it is expanded it is showing 5.
But when I am adding the debug points then it is showing the correct value . Does anyone have any idea why it is showing this strange behaviour ???
Thanks
Chrome's debugging tools will re-evaluate the object when you click to expand, so the expanded version shows what the object looks like at the time of the click, not at the time of the console.log. Apparently, the value changed in between when the console.log happened and when the click happened.
You are probably changing this object in your code, the first log is done instantly, right when you call console.log, but your object was mutated before you had the time to expand it.
To make sure the object logged is not mutated you can copy it before the log:
// not sure of your actual log code but:
console.log('==>', index, {...object})
// instead of just
console.log('==>', index, object)
Check this example:
const obj = { cnt: 0 };
console.log(obj);
(function loop() {
obj.cnt++;
setTimeout(loop, 50);
})();
It may be useful to understand what just happend:
It is worth to remember that JavaScript is asynchronous.

object as array element-the console log output is confusing [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is Chrome's JavaScript console lazy about evaluating arrays?
Chrome's js console is showing an array with a deleted value before the value is deleted. Why?
jsFiddle that demonstrates this behavior.
var list=[];
list.push("one");
list.push("two");
list.push("three");
console.log(list); //["two", "three", undefined × 1]
$("#output").append(JSON.stringify(list));//["one","two","three"]
list.shift();
$("#output").append($("<br>"));
console.log(list); //["two", "three"]
$("#output").append(JSON.stringify(list));//["two","three"]
​
In Chrome console.log is "delayed"; in this case to the end of the Program I believe.
That is, in Chrome, console.log does not stringify the input object immediately but rather performs the stringification "some time later" (after which the object has been modified in this case) but before it actually displays the result,
console.log(JSON.stringify(list)) would show the expected result.
This was reported as a bug as far back as Chrome 5 (the bug-fix target is Mstone-22, so not Chrome 20/21?) and a fix has been added to the webkit base:
As of today, dumping an object (array) into console will result in objects' properties being read upon console object expansion (i.e. lazily). This means that dumping the same object while mutating it will be hard to debug using the console.
This change starts generating abbreviated previews for objects / arrays at the moment of their logging and passes this information along into the front-end. This only happens when the front-end is already opened, it only works for console.log(), not live console interaction.

create an array from javascript variables

Hello I want to push some values into an array but when i alert that array it shows me [object,object],[object,object],[object,object],[object,object]
Does anyone know what the problem is?
Here is the code:
$(document).ready(function() {
$(":button").click(function(event){
var value = $('#box').val();
if (value==""){
return false;
}
else{$.getJSON("http://search.twitter.com/search.json?callback=?&q=value",
function(data){
var array=[];
$.each(data.results, function(i, item){
var user=item.from_user;
var created_at=item.created_at
array.push({date:'created_at',username:'user'});
});alert(array);
});
}
});});
There isn't a problem.
When you alert an object (which {date:'created_at',username:'user'} will create) it will be stringified to "[object object]". (You can change that by overriding the toString function of the object).
The array does contain the objects.
(OK, technically there is a problem, but the symptoms you describe are unrelated to it, the values you are putting in to the objects are string literals and not variables, you shouldn't quote them).
You are using strings instead of variables to create your object:
array.push({date:'created_at',username:'user'});
should be:
array.push({date:created_at,username:user});
or
array.push({date:item.created_at, username:item.from_user});
After creating the object, use console.log instead of alert for debugging. The default Object.toString() implementation, which gets called by alert, returns the [object Object] you are seeing.
First I spot a small bug in your code. When you create the object to push in the array you don't use the values but fixed strings (in upticks). You should alter that line to this version:
array.push({date:created_at, username:user});
If you try to visualize internal state (debugging information) then using alert() gives only a poor visual representation. Instead of alert() You could use console.log() instead.
This statement creates output in the console. Not every browser supports it. Internet Explorer has the developer tools. You can active them by simply pressing F12. But as far as I can see IE has very limited output. Firefox can be extended with the Firebug plugin (a very powerful tool!).
When you call console.log(array) in your code the output in Firebug shows something like this
[Object { date=..., username = ... }, Object { date = ..., username = ...}]
Since console.log() isn't supported by all browsers you should remove the calls before you release your sources in production.

console.log() shows the changed value of a variable before the value actually changes

This bit of code I understand. We make a copy of A and call it C. When A is changed C stays the same
var A = 1;
var C = A;
console.log(C); // 1
A++;
console.log(C); // 1
But when A is an array we have a different situation. Not only will C change, but it changes before we even touch A
var A = [2, 1];
var C = A;
console.log(C); // [1, 2]
A.sort();
console.log(C); // [1, 2]
Can someone explain what happened in the second example?
Console.log() is passed a reference to the object, so the value in the Console changes as the object changes. To avoid that you can:
console.log(JSON.parse(JSON.stringify(c)))
MDN warns:
Please be warned that if you log objects in the latest versions of Chrome and Firefox what you get logged on the console is a reference to the object, which is not necessarily the 'value' of the object at the moment in time you call console.log(), but it is the value of the object at the moment you open the console.
Pointy's answer has good information, but it's not the correct answer for this question.
The behavior described by the OP is part of a bug that was first reported in March 2010, patched for Webkit in August 2012, but as of this writing is not yet integrated into Google Chrome. The behavior hinges upon whether or not the console debug window is open or closed at the time the object literal is passed to console.log().
Excerpts from the original bug report (https://bugs.webkit.org/show_bug.cgi?id=35801):
Description From mitch kramer 2010-03-05 11:37:45 PST
1) create an object literal with one or more properties
2) console.log that object but leave it closed (don't expand it in the console)
3) change one of the properties to a new value
now open that console.log and you'll see it has the new value for some reason, even though it's value was different at the time it was generated.
I should point out that if you open it, it will retain the correct value if that wasn't clear.
Response from a Chromium developer:
Comment #2 From Pavel Feldman 2010-03-09 06:33:36 PST
I don't think we are ever going to fix this one. We can't clone object upon dumping it into the console and we also can't listen to the object properties' changes in order to make it always actual.
We should make sure existing behavior is expected though.
Much complaining ensued and eventually it led to a bug fix.
Changelog notes from the patch implemented in August 2012 (http://trac.webkit.org/changeset/125174):
As of today, dumping an object (array) into console will result in objects' properties being
read upon console object expansion (i.e. lazily). This means that dumping the same object while
mutating it will be hard to debug using the console.
This change starts generating abbreviated previews for objects / arrays at the moment of their
logging and passes this information along into the front-end. This only happens when the front-end
is already opened, it only works for console.log(), not live console interaction.
The latest guidance from Mozilla as of February 2023:
Don't use console.log(obj), use console.log(JSON.parse(JSON.stringify(obj))).
This way you are sure you are seeing the value of obj at the moment you log it. Otherwise, many browsers provide a live view that constantly updates as values change. This may not be what you want.
Arrays are objects. Variables refer to objects. Thus an assignment in the second case copied the reference (an address) to the array from "A" into "C". After that, both variables refer to the same single object (the array).
Primitive values like numbers are completely copied from one variable to another in simple assignments like yours. The "A++;" statement assigns a new value to "A".
To say it another way: the value of a variable may be either a primitive value (a number, a boolean, null, or a string), or it may be a reference to an object. The case of string primitives is a little weird, because they're more like objects than primitive (scalar) values, but they're immutable so it's OK to pretend they're just like numbers.
EDIT: Keeping this answer just to preserve useful comments below.
#Esailija is actually right - console.log() will not necessarily log the value the variable had at the time you tried to log it. In your case, both calls to console.log() will log the value of C after sorting.
If you try and execute the code in question as 5 separate statements in the console, you will see the result you expected (first, [2, 1], then [1, 2]).
Though it's not going to work in every situation, I ended up using a "break point" to solve this problem:
mysterious = {property:'started'}
// prints the value set below later ?
console.log(mysterious)
// break, console above prints the first value, as god intended
throw new Error()
// later
mysterious = {property:'changed', extended:'prop'}
The issue is present in Safari as well. As others have pointed out in this and similar questions, the console is passed a reference to the object, it prints the value of the object at the time the console was opened. If you execute the code in the console directly for example, the values print as expected.
Instead of JSON stringifying, I prefer to spread arrays (e.g. in your case console.log([...C]);) and objects: the result is quite the same, but the code looks a bit cleaner. I have two VS code snippets to share.
"Print object value to console": {
"prefix": "clo",
"body": [
"console.log(\"Spread object: \", {...$0});"
],
"description": "Prints object value instead of reference to console, to avoid console.log async update"
},
"Print array value to console": {
"prefix": "cla",
"body": [
"console.log(\"Spread array: \", [...$0]);"
],
"description": "Prints array value instead of reference to console, to avoid console.log async update"
}
In order to get the same output as with console.log( JSON.parse(JSON.stringify(c))), you can leave out the string part if you wish. Incidentally, the spread syntax often saves time and code.

console.log() showing contradictory values for the same object property

I think i might be going mad.
I use console.log() to see the state of an object and then on the next line do a console.log() on a particular property of the same object and get different values for each.
The code i'm using is:
console.log(this.pictures.Items[pic].val);
for(var i in this.pictures.Items[pic].val) {
console.log("property: %s, value: %s", i, this.pictures.Items[pic].val[i] );
}
and firebug outputs:
Picture { isLoaded=true, isSelected=false, img_src="imgs/image1.jpg", more...}
property: isLoaded, value: false
...more properties
as you can see, 'isLoaded' is true when logging the object itself but false when logging the property.
I have tried logging the object again after just in case, and it is true again.
Does anyone know what is happening here?
Thanks
Rich
I'm not entirely sure if this is what is happening to you or not, but console.log() seems to have some issues in some browsers where doing a console.log() on a value or using an index variable that is changing or being iterated in an array does not always work properly.
My guess is that it has something to do with things getting marshalled between process boundaries and perhaps a delay in the actual evaluation of the logging expression until a time in which the actual object or index being used or referenced has changed. I've seen this issue in Chrome for sure - don't know about Firefox.
You should be able to work around this particular issue by using string math to build your final string. If only the final string is passed to console.log() where everything is fully evaluated, then this issue would not impact the output.

Categories