weird array behaviour in javascript [duplicate] - javascript

This question already has answers here:
Is Chrome’s JavaScript console lazy about evaluating objects?
(7 answers)
Closed 1 year ago.
I know arrays in javascript are a bit special, compared to other languages, but I don't really get this behaviour, or what's going on here.
I'd like to know why it happens and why I don't get an empty array:
function setupWindowProgBar(settings, window, palette, arr){
console.log('start');
console.log(arr);
if(typeof arr == 'undefined'){
var arr = [];
}
console.log(arr);
console.log('stop');
var arrLen = arr.length;
arr[arr.length] = createProgBar('master', 'bg', window, 0, settings.fillColor, settings.strokeColor, settings.textColor, palette, 'percent', settings.reqType, settings.sourceType, settings.sourceTarget, settings.sourceId);
return arr;
}
produces this in the console:
start
undefined
[]
0:
barType:"master"
bgcolor:"#12181f"
curVal:160
data:
all_goals:160
cost_hours:160
cost_hours_spent:0
cost_money:31610
cost_money_owned:0
parentObj:"progBar"
progress_goals:5
recurring:"no"
wanted_timer:"2018-03-26 05:19:33"
__proto__:Object
fill:"#255f6f"
height:59
maxVal:5
maxWidth:168
sectionHeight:59
stroke:"#7b9dac"
text:"3%"
textColor:"#dee5ed"
textOpt:"percent"
width:200
x:33
y:81
__proto__:Object
height:100
text:"omanko"
length:1
__proto__:Array(0)
stop
I do reckognize the objects in here, but it's not from global pollution as far as I can tell - console.log(window.arr) says that there are no global variables named arr, and I haven't modified the prototype.
Surely, that shouldn't effect a new array declaration anyway?

This behaviour isn't limited to arrays, any object behaves this way in the console
What you are seeing is the result of console in all browsers "lying" to you
if you console.log(anyobject) and inspect that object in the console, what you will see is current anyobject - not what it was when console.log was executed
var obj = {}
console.log(obj);
obj.test = 1;
var arr = [1];
console.log(arr);
arr.push(2);
Now, if you open the developer console, click on the Object, you'll see test:1
Look at the array in the console - it is output as [1] ... yet, click on the array you see both elements
Note: chrome developer console does at least hint at the fact that it's lying to you - there's a blue i, if you hover (or click, can't recall, don't use Chrome often enough) you'll see a message saying that the value shown is evaluated just now

The issue is when you call console.log(arr) it puts a reference to the array in the console that gets dereferenced when you "open" it (click on the arrow) so it will display changes that are made later in code. Use console.table(arr) or console.log(JSON.stringify(arr)) instead.
Here is a snippet from MDN
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 click it open.

arr is a parameter to your function already, and it is not undefined. var gets hoisted, so to the interpreter, your current code actually looks something like:
function setupWindowProgBar(settings, window, palette, arr){
var arr; // **does not reassign the parameter**
console.log('start');
console.log(arr);
if(typeof arr == 'undefined'){
arr = [];
}
console.log(arr);
console.log('stop');
}
You should never be declaring a variable whose name is already scoped to the block/function you're using it in.
If arr actually isn't defined in the argument, then it will be assigned to an array on the line arr = [];, but at least on Chrome, that empty array will not necessarily be printed at the time you console.log it.
console.log(arr); does not necessarily immediately display the arr - depending on your browser, it may only be populated in your console after you open your console, after this line has run:
arr[arr.length] = createProgBar('master', 'bg', window, ...

Related

Why is this object changing before the function is run? [duplicate]

This question already has answers here:
Is Chrome’s JavaScript console lazy about evaluating objects?
(7 answers)
Closed 3 years ago.
I have an object with an array (of class objects) as one of its values. I have a function that, in part, runs a class method on one of the objects inside that array (within the object).
When I run my code, printing the array before and after the function, the change is both present before AND after the function runs.
Why is this happening? Hoisting?
As a test, I created another key:value pair in the object such that the value is an integer, and changed my function to just bump that integer up 1. Here, it works fine - the print of my object before the function has that integer as 1, and then afterward has the integer as 2.
I also tried NOT using a class method on the object to make the adjustment, and it still failed.
class Book{
constructor (color, title, pagecount){
this.color = color;
this.title = title;
this.pagecount = pagecount;
}
changePages() {
this.pagecount += 50;
}
}
let book1 = new Book("Red", "Book1", 100);
let book2 = new Book("Blue", "Book2", 200);
let book3 = new Book("Green", "Book3", 300);
var myBookArr = [book1, book2, book3]
var myObj = {arr: myBookArr, integerTest: 0}
function thisDoesStuff(){
//other operations not related to myObj
myObj.arr[0].changePages();
}
When I run the below, in BOTH console.logs, it shows that arr[0] (which is book1) has 150 pages.
console.log(myObj);
changePages();
console.log(myObj);
I am expecting the first console.log to show book1 as its original value, then the function changes it.
Please, hover on the icon with i letter on it near your log.
You will see, that Chrome (if you using Chrome, of course) will say:
Value below was evaluated just now
It happens because objects and other complex entities are being passed by reference, not by value. So, when you are expanding you log, browser getting up-to-date value of the reference.
Try to console.log copy of your value (e.g. console.log({...myObj})), or use JSON.stringify or other string-like representation of your object.
Note, that it is not error in your code. It is just a feature of the console.log, so (if I interpreted it correctly) your code works just fine :)
Your code is correct, it's all based off when the browser decides to evaluate the object for console.log output.
See post here that another user was having a similar question:
Weird behavior with objects & console.log

javascript window.document in the console [duplicate]

In Chrome the console object defines two methods that seem to do the same thing:
console.log(...)
console.dir(...)
I read somewhere online that dir takes a copy of the object before logging it, whereas log just passes the reference to the console, meaning that by the time you go to inspect the object you logged, it may have changed. However some preliminary testing suggests that there's no difference and that they both suffer from potentially showing objects in different states than when they were logged.
Try this in the Chrome console (Ctrl+Shift+J) to see what I mean:
> o = { foo: 1 }
> console.log(o)
> o.foo = 2
Now, expand the [Object] beneath the log statement and notice that it shows foo with a value of 2. The same is true if you repeat the experiment using dir instead of log.
My question is, why do these two seemingly identical functions exist on console?
In Firefox, these function behave quite differently: log only prints out a toString representation, whereas dir prints out a navigable tree.
In Chrome, log already prints out a tree -- most of the time. However, Chrome's log still stringifies certain classes of objects, even if they have properties. Perhaps the clearest example of a difference is a regular expression:
> console.log(/foo/);
/foo/
> console.dir(/foo/);
* /foo/
global: false
ignoreCase: false
lastIndex: 0
...
You can also see a clear difference with arrays (e.g., console.dir([1,2,3])) which are logged differently from normal objects:
> console.log([1,2,3])
[1, 2, 3]
> console.dir([1,2,3])
* Array[3]
0: 1
1: 2
2: 3
length: 3
* __proto__: Array[0]
concat: function concat() { [native code] }
constructor: function Array() { [native code] }
entries: function entries() { [native code] }
...
DOM objects also exhibit differing behavior, as noted on another answer.
Another useful difference in Chrome exists when sending DOM elements to the console.
Notice:
console.log prints the element in an HTML-like tree
console.dir prints the element in a JSON-like tree
Specifically, console.log gives special treatment to DOM elements, whereas console.dir does not. This is often useful when trying to see the full representation of the DOM JS object.
There's more information in the Chrome Console API reference about this and other functions.
None of the 7 prior answers mentioned that console.dir supports extra arguments: depth, showHidden, and whether to use colors.
Of particular interest is depth, which (in theory) allows travering objects into more than the default 2 levels that console.log supports.
I wrote "in theory" because in practice when I had a Mongoose object and ran console.log(mongoose) and console.dir(mongoose, { depth: null }), the output was the same. What actually recursed deeply into the mongoose object was using util.inspect:
import * as util from 'util';
console.log(util.inspect(myObject, {showHidden: false, depth: null}));
I think Firebug does it differently than Chrome's dev tools. It looks like Firebug gives you a stringified version of the object while console.dir gives you an expandable object. Both give you the expandable object in Chrome, and I think that's where the confusion might come from. Or it's just a bug in Chrome.
In Chrome, both do the same thing. Expanding on your test, I have noticed that Chrome gets the current value of the object when you expand it.
> o = { foo: 1 }
> console.log(o)
Expand now, o.foo = 1
> o.foo = 2
o.foo is still displayed as 1 from previous lines
> o = { foo: 1 }
> console.log(o)
> o.foo = 2
Expand now, o.foo = 2
You can use the following to get a stringified version of an object if that's what you want to see. This will show you what the object is at the time this line is called, not when you expand it.
console.log(JSON.stringify(o));
Use console.dir() to output a browse-able object you can click through instead of the .toString() version, like this:
console.dir(obj/this/anything)
How to show full object in Chrome console?
From the firebug site
http://getfirebug.com/logging/
Calling console.dir(object) will log an interactive listing of an object's properties, like > a miniature version of the DOM tab.
Following Felix Klings advice I tried it out in my chrome browser.
console.dir([1,2]) gives the following output:
Array[2]
0: 1
1: 2
length: 2
__proto__: Array[0]
While console.log([1,2]) gives the following output:
[1, 2]
So I believe console.dir() should be used to get more information like prototype etc in arrays and objects.
Difference between console.log() and console.dir():
Here is the difference in a nutshell:
console.log(input): The browser logs in a nicely formatted manner
console.dir(input): The browser logs just the object with all its properties
Example:
The following code:
let obj = {a: 1, b: 2};
let DOMel = document.getElementById('foo');
let arr = [1,2,3];
console.log(DOMel);
console.dir(DOMel);
console.log(obj);
console.dir(obj);
console.log(arr);
console.dir(arr);
Logs the following in google dev tools:
Well, the Console Standard (as of commit ef88ec7a39fdfe79481d7d8f2159e4a323e89648) currently calls for console.dir to apply generic JavaScript object formatting before passing it to Printer (a spec-level operation), but for a single-argument console.log call, the spec ends up passing the JavaScript object directly to Printer.
Since the spec actually leaves almost everything about the Printer operation to the implementation, it's left to their discretion what type of formatting to use for console.log().

javascript's object property member change so strangely [duplicate]

This question already has an answer here:
Javascript Console Log reporting object properties incorrectly
(1 answer)
Closed 5 years ago.
var obj = {name:"小明"};
console.log("obj1",obj);
// 1. {name:"小明",age:10}
obj.age = 10;
console.log("obj2",obj);
// 2. {name:"小明",age:10}
why does the browser console display the result at the first? I think the reuslt should be an unchanged object {name:"小明"}.Now ,I have a headache about it . appreciate your response.
This is because you are seeing/expanding the object after adding the new property age.
Initially the object has only one property but by the time you are inspecting it , a new key will be added to the object
Another way is to verify using hasOwnProperty. In below snippet the first console.log statement won't be executed since the object does not have the key age
var obj = {
name: "小明"
};
if (obj.hasOwnProperty('age')) {
console.log("obj1", obj);
}
obj.age = 10;
console.log("obj2", obj);
This depends on the browser. If I recall correctly, chrome logs an unchanging object whereas firefox logs a changing one. Either way, obj.age will be undefined until you define it.
When you expand the object the values displayed in the console are evaluated at runtime.
Tooltip in Chrome console explaining that values are evaluated at runtime:
You could try JSON.stringify to print the current value to the console.
e.g.
console.log("obj1", JSON.stringify(obj));

is there a way to refer to outputted object in dev console of chrome

Lot of times when I output an object in chrome using console.log(). It outputs the object and its properties in expandable tree format, which is nice. But is there a way to refer to it in console?...Like in console you can refer to Dom elements....as $0, $1, $2..etc.
Is there a way to refer to outputted objects so I can use them within in console by referring to them like: $c.obj1.someProperty..
This can be very useful when I am learning new Api, and debugging the object.
One approach would be to assign it to the window object under some property. Consider a function as follows:
function addDebugObject(obj) {
var index;
if (!window.debugObjects) {
window.debugObjects = [];
}
index = window.debugObjects.length;
window.debugObjects.push(obj);
console.log(index, obj);
}
Then to use it in the console
> addDebugObject({'d': 4})
0 [Object]
> obj = window.debugObjects[0]
{'d': 4}
You can refer to the last result using $_ (dollar-underscore).
(defined here)

Are JavaScript/ECMAScript arrays "sparse" in Node.js?

My question is the same as Are Javascript arrays sparse? with one difference...
Are JavaScript arrays sparse, as implemented in Node.js (and/or V8)? I had assumed the were, but then I did the following test:
var testArray = [];
testArray[10000] = 'test';
console.log(testArray);
Returned is 10,000 blank elements, with 'test' at the end. Is this because of the way the debugging output works, or does Node.js actually allocate memory for the undefined array elements when adding new elements?
What you are seeing is not an actual array, just a representation. The console checks for the presence of a length and a splice property and prints the numeric properties of the object, which is why jQuery collections appear to be arrays when logged.
function RandomThingThatIsDefinitelyNotAnArray() {
this.splice = function() {};
this.length = 10;
this[5] = 5;
}
console.log(new RandomThingThatIsDefinitelyNotAnArray());​
// shows [undefined, undefined, undefined, undefined, undefined, 5]
jsfFiddle for a live demo.
Node's util.inspect function specifically checks for sparse arrays to print them like that. In fact, it has a test that specifically checks for it. I know this because my full rewrite of node's inspector ultimately didn't make it into core, and lead to my UltraREPL.

Categories

Resources