JavaScript: почему цикл for выполняет выбор переменных из __proto__? - PullRequest
5 голосов
/ 16 мая 2019

Я добавил метод trigger к прототипу объекта:

Object.prototype.trigger = function() {
    //  ...
    return this;
};

И затем есть цикл for:

var obj = { 4: 15, 10 : 41, 11 : 46, 12 : 51, 20 : 74 }
for( item in obj ) {
    foo( obj[item] );
}

Но этот цикл имеет 6 итераций вместо 5. Последняя итерация с ключом:

item = "trigger"

Почему цикл повторяется по части __proto__ объекта?

Ответы [ 4 ]

2 голосов
/ 16 мая 2019

for...in охватывает все свойства объекта, не различая свойства самого объекта или любого из его предков.

Чтобы перейти только к свойствам, определенным для самого объекта, вы можете использовать Object.prototype.hasOwnProperty:

const obj = { 4: 15, 10 : 41, 11 : 46, 12 : 51, 20 : 74 }
for( item in obj ) {
  if(obj.hasOwnProperty(item) {
    foo( obj[item] );
  }
}

// will ignore the trigger func and everything else defined on any prototype
2 голосов
/ 16 мая 2019

for..in выполняет итерации по всем перечислимым свойствам в любом месте цепочки прототипов.Если вы хотите сделать trigger не перечисляемым, чтобы оно не повторялось с for..in, используйте вместо этого Object.defineProperty, что делает определенное свойство не перечисляемым по умолчанию:

Object.defineProperty(Object.prototype, 'trigger', { value:  function() {
    
}});
var obj = { 4: 15, 10 : 41 }
for( item in obj ) {
    console.log(item);
}
1 голос
/ 16 мая 2019

Другой способ - использовать Object.keys вместо:

Object.prototype.trigger = function() {
    return this;
};

var obj = { 4: 15, 10 : 41, 11 : 46, 12 : 51, 20 : 74 }

Object.keys(obj).forEach(function(item) {
    console.log( "Key: " + item + ", value: " + obj[item] );
});
0 голосов
/ 16 мая 2019

Это была ошибка, с которой я столкнулся с массивами некоторое время назад. Поскольку массивы также являются объектами, и вы можете перейти в прототип, не используйте for..in для массивов. Ваш пример относится к объекту, который вызывает эту проблему. Вместо этого используйте стандартный for, чтобы перебрать элементы вашего объекта. Таким образом, вы могли бы иметь более чистую и безопасную реализацию для того, чего пытаетесь достичь, вместо использования defineProperty или hasOwnProperty, которые в основном используются для реализации отражения.

for (var i = 0; i < Object.values(obj).length; i++){
  console.log(i + ': ' + Object.values(obj)[i]);
  //foo( Object.values(obj)[i] );
}
...