JavaScript: скрытие методов-прототипов для цикла?

Допустим, я добавил несколько методов-прототипов в класс Array:



Array.prototype.containsKey = function(obj) {
    for(var key in this)
        if (key == obj) return true;
    return false;
}

Array.prototype.containsValue = function(obj) {
    for(var key in this)
        if (this[key] == obj) return true;
    return false;
}

Затем я создаю ассоциативный массив и пытаюсь перебрать его ключи:



var arr = new Array();
arr['One'] = 1;
arr['Two'] = 2;
arr['Three'] = 3;

for(var key in arr)
   alert(key);

это возвращает пять пунктов:

  -Один
  -Два
  -Три
  -containsKey
  -containsValue

но я хочу (ожидаю?) только три. Я подхожу к этому неправильно? Есть ли способ "спрятать" методы-прототипы? или я должен делать что-то по-другому?

7 ответов

Решение

Вы можете использовать JavaScript-метод hasOwnProperty для достижения этого в цикле, например:

for(var key in arr) {
    if (arr.hasOwnProperty(key)) {
        ...
    }
}

Ссылка: Эта статья в блоге YUI.

Вы можете достичь желаемого результата с другого конца, сделав методы-прототипы не перечисляемыми:

Object.defineProperty(Array.prototype, "containsKey", {
  enumerable: false,
  value: function(obj) {
      for(var key in this)
        if (key == obj) return true;
      return false;
    }
});

Обычно это работает лучше, если у вас есть контроль над определениями методов, и, в частности, если у вас нет контроля над тем, как ваш код будет вызываться другими людьми, что является распространенным предположением при разработке кода библиотеки.

Javascript не поддерживает ассоциативные массивы так, как вы думаете. http://ajaxian.com/archives/javascript-associative-arrays-considered-harmful

for (var i in.. получает все свойства объекта (массив - это просто еще один объект), поэтому вы видите другие объекты, которые вы ему создали.

Как говорится в статье, вы должны использовать объект:


var assoc = {'One' : 1, 'Two' : 2};
assoc['Three'] = 3;

for(var key in assoc)
   alert(key+' => '+assoc[key]);

Вы могли бы сделать это:

for(var key in arr)
{
   if (typeof(arr[key]) == "function")
      continue;
   alert(key);
}

Но это плохой обходной путь

Метод 1: использовать Object.keys (который не возвращает свойства прототипа) и цикл

Object.keys(arr); // ['One', 'Two', 'Three']
Object.keys(arr).forEach(key => console.log(key))

Способ 2: hasOwnProperty внутри цикла for.

 for(var key in arr) {
   if (arr.hasOwnProperty(key)) {
     ...
   }
 }

Вы можете скрыть методы, добавленные в прототип, из циклов for-in следующим образом:

      Object.defineProperty(Array.prototype, "containsKey", { enumerable: false });

Сразу после добавления метода. где «containsKey» — ваш добавленный метод.

Для высокопроизводительной итерации по массивам JavaScript используйте либо for или же while петля. Николас Закас обсуждает наиболее эффективные варианты перебора массивов в своем Tech Talk Speed ​​Up Your JavaScript.

Ваша лучшая ставка, вероятно, примерно такая:

for (var i = collection.length - 1; i >= 0; i--) {
  if (obj == collection[i]) return true;
}

Этот подход будет лучше всего по нескольким причинам:

  • Выделена только одна локальная переменная
  • Коллекция length свойство доступно только один раз, при инициализации цикла
  • Каждую итерацию локальное сравнивают с константой (i >= 0) вместо другой переменной
Другие вопросы по тегам