Как определить метод в JavaScript для Array.prototype и Object.prototype, чтобы он не появлялся в цикле for
Я хочу определить вспомогательные методы для Array.prototype и Object.prototype. Мой текущий план - сделать что-то вроде:
Array.prototype.find = function(testFun) {
// code to find element in array
};
Так что я могу сделать это:
var arr = [1, 2, 3];
var found = arr.find(function(el) { return el > 2; });
Это работает нормально, но если я зациклюсь на массиве в for in
В цикле методы отображаются в виде значений:
for (var prop in arr) { console.log(prop); }
// prints out:
// 1
// 2
// 3
// find
Это испортит всех, кто полагается на for in
просто показать значения (особенно на объектах). Более поздние версии javascript имеют встроенные в массивы функции.map и.filter, но они не отображаются на for in
петли. Как я могу создать больше таких методов, которые не будут отображаться в for in
цикл?
3 ответа
Это довольно просто: не используйте циклы for-in с массивами. Обвиняйте всех остальных, кто так поступает - вот хороший фрагмент, чтобы рассказать им во время разработки.
Конечно, если кто-то выполняет перечисление в универсальной функции и не знает, получает ли он массив, простой объект или объект с пользовательским прототипом, вы можете использовать hasOwnProperty
как это:
for (var prop in anyObj )
if (Object.prototype.hasOwnProperty.call(anyObj, prop))
// do something
Обратите внимание на явное использование Object.prototype
чтобы получить функцию - могут быть объекты, которые ее перезаписывают (особенно в картах данных, значение может даже не быть функцией), объекты, которые ее не поддерживают, или объекты, которые вообще не наследуются от Object.prototype. Смотрите также здесь.
Тем не менее, только автор сценария, который знает о проблеме, отфильтрует все его циклы for-in-loop - а некоторые делают это только потому, что это рекомендуется - и делает это в основном неправильно, он должен был бы использовать вместо этого итерацию массива for-loop. Но наша проблема - это те авторы, которые об этом не знают.
Интересный, но только для Mozilla подход заключается в перезаписи поведения перечислений в массивах с помощью __iterate__
, как показано здесь.
К счастью, EcmaScript 5.1 позволяет нам устанавливать свойства не перечисляемыми. Конечно, это не поддерживается в старых браузерах, но зачем? В любом случае нам нужно было бы использовать es5-shims для всех классных массивов высшего порядка:-) defineProperty
как это:
Object.defineProperty(Array.prototype, "find", {
enumerable: false,
writable: true,
value: function(testFun) {
// code to find element in array
}
});
В зависимости от ваших ограничений:
// In EcmaScript 5 specs and browsers that support it you can use the Object.defineProperty
// to make it not enumerable set the enumerable property to false
Object.defineProperty(Array.prototype, 'find', {
enumerable: false, // this will make it not iterable
get: function(testFun) {
// code to find element in array
};
});
Узнайте больше о Object.defineProperty здесь https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty
Приведенные выше ответы упускают точку:
enumerable... по умолчанию false( мдн)
Так просто используя Object.defineProperty(Array.prototype, 'myFunc' myFunc)
вместо Array.prototype.myFunc = myFunc
решит проблему.
Это потому, что нужно проверить hasOwnProperty
:
for (var prop in arr) {
if (arr.hasOwnProperty(prop)) {
console.log(prop)
}
}
Теперь это журналы 1, 2, 3.