Как определить метод в 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.

Другие вопросы по тегам