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
) вместо другой переменной