Javascript: скрывать методы прототипа in for loop?

Итак, скажем, я добавил некоторые методы прототипа в класс 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);

это возвращает пять элементов:

  -One
  -Two
  -Three
  -containsKey
  -containsValue

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

Ответ 1

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

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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


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

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

Ответ 4

вы можете сделать это:

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

Но это дрянное обходное решение

Ответ 5

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

Лучше всего, наверное, что-то вроде этого:

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

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

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