Допустимо ли вызывать Array.map для итерируемого объекта, который не является массивом? - PullRequest
0 голосов
/ 05 июня 2018

Эта статья: Обход DOM с помощью функций filter (), map () и стрелок поддерживает такое использование Array.map, что мне кажется странным.В частности, автор статьи утверждает, что следующий фрагмент кода является действительным и действительно лучше, чем альтернатива Array.from(elements).map(...):

var elements = document.getElementsByClassName("bgflag");
BgFlags = Array.prototype.map.call(elements,
        element =>
        ({
            height: element.offsetTop,
            bgsrc: element.dataset.bgsrc,
            bgcolor: element.dataset.bgcolor,
            size: element.dataset.size,
            name: element.id,
            image: parseInt(element.dataset.image)
        })
    );

Это кажется наиболее подозрительным для моего неподготовленного глаза.Мы звоним Array.prototype.map на что-то, что не Array.Если где-то прямо не указано, что это разрешено, это пахнет как неопределенное поведение для меня.Я быстро просмотрел соответствующую документацию MDN , но не смог найти, что такое использование там разрешено.

И все же автор статьи подчеркивает:

Несмотря на то, что map () является функцией Array.prototype, она работает на любом итерируемом массиве.

Является ли такое использование допустимым, как он утверждает?Если да, то относится ли это к другим Array.prototype.* функциям, таким как filter, slice, может быть, даже pop, push, другим?

Ответы [ 2 ]

0 голосов
/ 05 июня 2018

Если где-то явно не указано, что это разрешено

То есть, это в спецификации :

The map функция намеренно общая;это не требует, чтобы его значение this было Array объектом.Поэтому он может быть передан другим объектам для использования в качестве метода.

Большинство методов в Array.prototype имеют это примечание.Те, которые не могут быть использованы таким образом, не имеют такой заметки.

То, хотите ли вы использовать это, поэтому, это вопрос стиля.Разные люди по-разному говорят о том, хороший это / плохой / безразличный стиль.


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

const map = Function.prototype.call.bind(Array.prototype.map);

, а затем используйте его так:

const result = map(arrayLike, e => /*...*/);

Live Пример:

const map = Function.prototype.call.bind(Array.prototype.map);

const arrayLike = {
  0: "zero",
  1: "one",
  2: "two",
  length: 3
};
const result = map(arrayLike, e => e.toUpperCase());
console.log(result);
0 голосов
/ 05 июня 2018

Да, это обычно работает.Однако я согласен с вами, что:

Array.from(elements).map(element => /*..*/);
// Or even
Array.from(elements, element => /*...*/);

намного чище.

...