Неявно глобальная переменная "item" - разница между Internet Explorer и FireFox

Просто из любопытства.

У меня есть этот JS-код:

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);

Обратите внимание на комментарий var item, который оставляет цикл с неявно объявленной переменной item.

  • Если я запустил этот код в FireFox, результатом будет предупреждение: 0:a,1:b,2:c

  • Если я запустил тот же код в Internet Explorer, результатом будет: 0:c,1:c,2:c

Вот jsfiddle: https://jsfiddle.net/fvu9gb26/

Конечно, когда я раскомментирую var item, он работает одинаково в каждом браузере.

Кто-нибудь знает, почему эта разница происходит? Спасибо.

Ответы

Ответ 1

В основном, поскольку объект Internet Explorer window предоставляет метод item(), который ваш script не может перезаписать.

В строке:

item = new Object();

item не объявляется в локальной области, поэтому он интерпретируется как свойство глобального объекта (window.item). В Firefox window не выставляет член с именем item, поэтому вводится новый член и ему присваивается результат new Object().

С другой стороны, Internet Explorer предоставляет собственный метод с именем window.item(). Этот член не может быть записан, поэтому назначение не может быть выполнено - оно игнорируется. Другими словами, item = new Object() не имеет никакого эффекта (ну, он создает объект, но не может назначить его впоследствии).

Последующие назначения id и name завершают создание новых членов метода item(). Это всегда одни и те же члены одного и того же метода, поэтому их значения перезаписываются на каждой итерации цикла. Кроме того, тот же объект (метод item()) помещается в массив на каждой итерации.

Следовательно, массив заканчивается, содержащий три раза один и тот же объект, а значения его членов id и name являются последними присвоенными им значениями (в последней итерации) соответственно 3 и 'c'.

Ответ 2

Это сложно. По какой-то непонятной причине Internet Explorer имеет собственный метод item в глобальном контексте window (если кто-то знает, почему вы можете делиться: я не могу найти его в документации). Итак, когда вы используете идентификатор item без объявления переменной, он ссылается на этот метод.

Первая инструкция в цикле (item = new Object();) ничего не делает, потому что window.item является свойством readonly. Итак, после этой инструкции window.item по-прежнему является нативной функцией.

Следующие команды (те, которые устанавливают id и name) работают, потому что, пока свойство window.item доступно только для чтения, объект Function, на который он указывает, может быть изменен.

После циклов вы добавили один и тот же объект Function три раза, и только последняя итерация подсчитывается, потому что вы каждый раз переопределяете свойства id и name.