Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicitly global "item" variable - difference between Internet Explorer and FireFox

Just out of curiosity..

I have this JS code:

var someExternalArray = [{id: 1, name: 'a'}, {id: 2, name: 'b'}, {id: 3, name: 'c'}];
var newArray = []

//var item;
for (var i = 0; i < someExternalArray.length; i++){
    item = new Object();
    item.id = someExternalArray[i].id;
    item.name = someExternalArray[i].name;
    newArray.push(item);
}

alert('0:' + newArray[0].name + ',1:' + newArray[1].name + ',2:' + newArray[2].name);

Notice the commented var item which leaves the loop with implicitly declared item variable.

  • If I run this code on FireFox, the result of alert is: 0:a,1:b,2:c

  • If I run the same code in Internet Explorer, the result is: 0:c,1:c,2:c

Here is jsfiddle: https://jsfiddle.net/fvu9gb26/

Of course, when I uncomment the var item it works the same way in every browser.

Does anyone know why this difference occurs? Thank you.

like image 929
Ivan Sivak Avatar asked Mar 25 '15 10:03

Ivan Sivak


2 Answers

Basically, that's because Internet Explorer's window object exposes an item() method that your script cannot overwrite.

In the line:

item = new Object();

item is not declared in the local scope, so it is interpreted as a property of the global object (window.item). On Firefox, window does not expose a member named item, so a new member is introduced and the result of new Object() is assigned to it.

On the other hand, Internet Explorer exposes a native method named window.item(). That member is not writeable, so the assignment cannot take place -- it is silently ignored. In other words, item = new Object() has no effect at all (well, it does create an object but cannot assign it afterwards).

The subsequent assignments to id and name end up creating new members of the item() method. These are always the same members of the same method, so their values are overwritten on every loop iteration. In addition, the same object (the item() method) is pushed to the array on every iteration.

Therefore, the array ends up containing three times the same object, and the values of its id and name members are the last values assigned to them (in the last iteration), respectively 3 and 'c'.

like image 173
Frédéric Hamidi Avatar answered Nov 10 '22 12:11

Frédéric Hamidi


This is tricky. For some obscure reason, Internet Explorer has a native method called item in the global context window (if someone knows why, you're welcome to share: I can't find it in the documentation). So, when you use the identifier item without declaring a variable, it refers to this method.

The first instruction in the loop (item = new Object();) does nothing because window.item is a readonly property. So, after this instruction, window.item is still the native function.

The next instructions (those which sets id and name) works, because while the property window.item is readonly, the Function object it's pointing to can be modified.

After the loops, you added the same Function object three times, and only the last iteration counts because you override the id and name properties everytime.

like image 34
Sebastien C. Avatar answered Nov 10 '22 11:11

Sebastien C.