2

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?

Daniel Bengtsson
  • 302
  • 1
  • 3
  • 12
  • That should not happen, since `arr` should be an empty array at the point you log it, not a strange object. I'm sure you've omitted crucial parts of your code. – CertainPerformance Apr 15 '18 at 04:54
  • I agree, it shouldn't happen - will add the entire function for clarity – Daniel Bengtsson Apr 15 '18 at 04:56
  • It just makes no sense to me at all – Daniel Bengtsson Apr 15 '18 at 04:58
  • no, @Tigger it IS an array, what I want to know is why arr[0] is populated with a nested object. Where does this pollution come from, if not from the global scope? – Daniel Bengtsson Apr 15 '18 at 05:04
  • the console lies - in chrome console (if you're using chrome), it even tells you that the displayed object is evaluated "just now" - so, in the console you see `arr[0]` as the result of `createProgBar` - despite console.log appearing earlier – Jaromanda X Apr 15 '18 at 05:11

3 Answers3

3

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

Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • That's the answer I guess. – Animesh Kumar Apr 15 '18 at 05:22
  • But I see another weird behavior in Chrome. `var obj; console.log(obj); obj = {test: 1};` This code prints *undefined* rather than obj's current value – Animesh Kumar Apr 15 '18 at 05:24
  • yes, because it is `undefined` - and a **new** object is assigned, therefore the `console` won't show this new object "later" - so, there's actually nothing weird about that at all – Jaromanda X Apr 15 '18 at 05:26
  • Ah! Okay. Got it. If I write `var obj = {}; console.log(obj); obj.a = 2`, I guess what it is probably doing is that it is maintaining a reference to the **obj** object and outputs the current value of that object. – Animesh Kumar Apr 15 '18 at 05:29
  • 1
    yes, that is exactly the code I posted, except you used a property called `a` and I used `test` ... `test` isn't something special – Jaromanda X Apr 15 '18 at 05:30
  • yeah, I tested it with alert(); just to be sure, and sure enough - it does have the expected result when it's being called. Thanks @JaromandaX , it looked really weird there for a while - also, thanks for your input yesterday. A++ – Daniel Bengtsson Apr 15 '18 at 05:43
0

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, ...
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • just one quick followup question though, how come the first console.log(arr); before the if statement returns "undefined"? – Daniel Bengtsson Apr 15 '18 at 05:10
  • @DanielBengtsson Exactly what I am wondering. The first `console.log(arr)` prints `undefined`. – Animesh Kumar Apr 15 '18 at 05:11
  • `arr is a parameter to your function already, and it is not undefined` what if it is? i.e. you call using `setupWindowProgBar(settings, window, palette)` – Jaromanda X Apr 15 '18 at 05:14
  • I added this: console.log('test'); in the if statement - it DOES run. – Daniel Bengtsson Apr 15 '18 at 05:14
  • @Ooops, missread - yes, you are correct - sometimes it is. I know the logic is messed up, and I am refactoring the code now, and I don't have a problem fixing it - I am more so interested in WHY it happens so I know how to use/avoid it in the future. – Daniel Bengtsson Apr 15 '18 at 05:19
  • sure, my point was that just because you have `x` as a function argument doesn't mean it **wont be undefined**, as implied by the answer – Jaromanda X Apr 15 '18 at 05:22
  • @DanielBengtsson See edit - the issue is (quite likely) with Chrome's console, not with your Javascript's logic. – CertainPerformance Apr 15 '18 at 05:22
  • it's not "chrome console", and it's not an issue ... it's any console, and it's expected behaviour :p – Jaromanda X Apr 15 '18 at 05:28
  • and `that empty array will not necessarily be printed at the time you console.log it` - actually, it **will** log an empty array - but when you check the array in the console, you will get the **current** state, not the state at the time of the console.log – Jaromanda X Apr 15 '18 at 05:29
0

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.

Moti Korets
  • 3,738
  • 2
  • 26
  • 35