7

Can someone explain the following two outputs?

Code 1:

console.log(itemsAry);
//loadNextItem();
function loadNextItem(){
    var item = itemsAry.shift();
    console.log(item);
}

Result:

["cat-53", "cat-57", "cat-51", "cat-10", "cat-55", "cat-56", "cat-5", "cat-50", "cat-3", "cat-54", "cat-52", "cat-9", "cat-8", "cat-4", "cat-58", "cat-6", "cat-7"]

(as expected).

Code 2:

console.log(itemsAry);
loadNextItem();
function loadNextItem(){
    var item = itemsAry.shift();
    console.log(item);
}

Result:

["cat-57", "cat-51", "cat-10", "cat-55", "cat-56", "cat-5", "cat-50", "cat-3", "cat-54", "cat-52", "cat-9", "cat-8", "cat-4", "cat-58", "cat-6", "cat-7"]

cat-53

Notice that cat-53 has been shifted from the original array PRIOR to the console.log() output that is supposed to be occurring BEFORE the shift operation ever takes place. How i this possible? Or what am I missing?

EDIT: it gets worse:

console.log(itemsAry);
loadNextItem(); loadNextItem(); loadNextItem(); loadNextItem();
function loadNextItem(){
    var item = itemsAry.shift();
    console.log(item);
    console.log(itemsAry);
}

Result:

["cat-55", "cat-56", "cat-5", "cat-50", "cat-3", "cat-54", "cat-52", "cat-9", "cat-8", "cat-4", "cat-58", "cat-6", "cat-7"]
cat-53
["cat-55", "cat-56", "cat-5", "cat-50", "cat-3", "cat-54", "cat-52", "cat-9", "cat-8", "cat-4", "cat-58", "cat-6", "cat-7"]
cat-57
["cat-55", "cat-56", "cat-5", "cat-50", "cat-3", "cat-54", "cat-52", "cat-9", "cat-8", "cat-4", "cat-58", "cat-6", "cat-7"]
cat-51
["cat-55", "cat-56", "cat-5", "cat-50", "cat-3", "cat-54", "cat-52", "cat-9", "cat-8", "cat-4", "cat-58", "cat-6", "cat-7"]
cat-10

After testing in FireFox, it appears to be a Google Chrome issue specifically. FF output:

["cat-53", "cat-57", "cat-51", "cat-10", "cat-55", "cat-56", "cat-5", "cat-50", "cat-3", "cat-54", "cat-52", "cat-9", "cat-8", "cat-4", "cat-58", "cat-6", "cat-7"]
cat-53
["cat-57", "cat-51", "cat-10", "cat-55", "cat-56", "cat-5", "cat-50", "cat-3", "cat-54", "cat-52", "cat-9", "cat-8", "cat-4", "cat-58", "cat-6", "cat-7"]
cat-57
["cat-51", "cat-10", "cat-55", "cat-56", "cat-5", "cat-50", "cat-3", "cat-54", "cat-52", "cat-9", "cat-8", "cat-4", "cat-58", "cat-6", "cat-7"]
cat-51
["cat-10", "cat-55", "cat-56", "cat-5", "cat-50", "cat-3", "cat-54", "cat-52", "cat-9", "cat-8", "cat-4", "cat-58", "cat-6", "cat-7"]
cat-10
["cat-55", "cat-56", "cat-5", "cat-50", "cat-3", "cat-54", "cat-52", "cat-9", "cat-8", "cat-4", "cat-58", "cat-6", "cat-7"]

Output as expected...

Tom Auger
  • 19,421
  • 22
  • 81
  • 104

4 Answers4

4

Am I right in thinking you're using Chrome? Firebug doesn 't do this (I just checked - FF8.0, FB 1.8.4) but Chrome 16 does.

I think what's happening is that in Chrome, the console.log() is executed asynchronously, so as not to interrupt your code or something; effectively, all the console.log()s happen at once after the code that called them has finished running.

Edit: curses, ninja'd!

N3dst4
  • 6,360
  • 2
  • 20
  • 34
3

console.log is always a little "late" and you can't count on it when it comes to objects. Only primitives (strings etc.) will work directly. Of the former there is only one instance in memory, so when the console is fetching the data it may have changed already.

Of course, it depends on which console you're actually using, but I'm frequently experiencing this on Chrome.

Here is someone who experienced this on Firebug.

pimvdb
  • 151,816
  • 78
  • 307
  • 352
  • @Tom Auger, @pimvdb `console.log` is not 'late', but it output the `object` in the execution scope just as closure does. – steveyang Nov 15 '11 at 15:36
  • If you have a situation where it is an issue, you can `console.log(JSON.stringify(itemsAry));` and it will be fine. It is the expansion of non-scalar types that is delayed and there is a tiny `{i}` that pops out when you expand the output which says "the item below was evaluated just now" – user9645 Jun 16 '17 at 19:41
1

The behavior of console.log

The console.log snapshots element in the execute scope and print them in the console. An demonstration is here:

(function () {
  console.log(obj);
  var obj= {};
  obj.new_value = 'hello';
}())

obj is not defined when console.log is called. But it is printed into the console with the right property new_value.

The problem with firefox

First, when use function keyword to declare a function in firefox, the name of the function won't be assigned until execution of the code.

If you didn't define loadNextItem in your previous code, the following code will generate an error(ReferenceError: loadNextItem is not defined) in firefox.

loadNextItem();

function loadNextItem (){
    var item = itemsAry.shift();
    console.log(item);
}

This behavior is stated in ECMA-262

Several widely used implementations of ECMAScript are known to support the use of FunctionDeclaration as a Statement. However there are significant and irreconcilable variations among the implementations in the semantics applied to such FunctionDeclarations. Because of these irreconcilable differences, the use of a FunctionDeclaration as a Statement results in code that is not reliably portable among implementations.

And firefox doesn't support this behavior.

steveyang
  • 9,178
  • 8
  • 54
  • 80
  • Are you suggesting that Firefox will not execute a function unless that function has been defined FIRST (in the code)? – Tom Auger Nov 15 '11 at 16:30
  • Not really. If you use **function literals** `var myFunc = function() {}`, you could use them anywhere within the scope. – steveyang Nov 15 '11 at 16:41
  • It just doesn't bear up, I'm afraid. Even the simplest test case succeeds where you say it will fail. I'm not really sure what browser version you're testing in, but on recent versions of FF (6+ at any rate) you can call a function well in advance (in the code) from place in which you define it. – Tom Auger Nov 16 '11 at 21:56
  • Hi, Tom, I tested on FF7.0, with the following code `var itemsAry = [1,2,3]; loadNextItem(); function loadNextItem () { var item = itemsAry.shift(); console.log(item); }; ` Could you provide me the test cases you are using ? It is a serious issue against my understanding of function declaration in JS. – steveyang Nov 17 '11 at 03:45
  • I've tried the exact same code that you cite and it works as expected. Note that I'm testing in FF8, but I have been using functions before declaring them for years in JavaScript and have never encountered this issue. It has to do with the interpreter, I believe - it does a first pass to compile all the functions and then it executes. So it should never be an issue. – Tom Auger Nov 17 '11 at 14:02
  • Uhm... according to [this article](http://statichtml.com/2011/spidermonkey-function-hoisting.html), `function` declaration **with in** blocks aren't supported by FF8. Could you test that? I will also so some research and edit this post. – steveyang Nov 17 '11 at 16:15
  • Function declarations within blocks are CERTAINLY not legal ECMAScript (unless it's of the var fn = function() { } variety). I'm not sure where you got the impression that anyone was trying to declare a function within another function block? – Tom Auger Nov 17 '11 at 16:36
0

Unable to duplicate in FF 8.0 using

x = [1,2,3,4,5];
console.log(x);
y();
function y() {
    z = x.shift();
    console.log(z);
}
Marc B
  • 356,200
  • 43
  • 426
  • 500