1

This article: Traversing the DOM with filter(), map(), and arrow functions advocates such a use of Array.map that seems odd to me. More specifically, the author of the article claims the following piece of code is valid and actually better than the alternative 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)
        })
    );

This seems most suspicious to my untrained eye. We are calling Array.prototype.map on something that is not an Array. Unless it is somewhere explicitely stated that this is allowed, this smells like undefined behavior to me. I quickly scanned through the relevant MDN documentation, but couldn't find that such a usage is allowed there.

And yet, the author of the article underlines:

Even though map() is a function of Array.prototype, it works on any array-like iterable.

Is such a use valid, as he claims? If so, is this also the case with other Array.prototype.* functions, like filter, slice, maybe even pop, push, others?

2
  • Yes it is valid and an extremely common practice. Commented Jun 5, 2018 at 17:28
  • 2
    From the ES 5.1 spec: The map function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the map function can be applied successfully to a host object is implementation-dependent. Commented Jun 5, 2018 at 17:30

2 Answers 2

3

Unless it is somewhere explicitely stated that this is allowed

It is, it's in the specification:

The map function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method.

Most of the methods on Array.prototype have that note. The ones that can't be used that way don't have that note.

Whether you want to use it, therefore, is purely a matter of style. Different people will come down different ways on whether it's good/bad/indifferent style.


Side Note: If you're going to use map that way, rather than write that longhand each time, give yourself a shortcut:

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

and then use it like this:

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

Live Example:

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);

Sign up to request clarification or add additional context in comments.

Comments

1

Yes that generally works. However I agree to you that:

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

is much cleaner.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.