TL;DR: Basically, I'm trying to use Array.prototype.map()
to call a method mon to a list of context objects.
Say I have some code like this:
a.doSomething();
b.doSomething();
c.doSomething();
d.doSomething();
e.doSomething();
...
This is overly verbose. I want to be able to shorten this code up to something like this
[a, b, c, d, e].map(doSomething);
because I don't want to have to use a for
loop.
How would I be able to do this with the native map
function in JS, without any external libraries?
Thank you in advance! If this post is too long, I will happily edit it. Just scream at me.
Related questions:
How to use map() to call class methods on a list of objects
How to call same method for a list of objects?
I didn't use the info in the related questions because Python and JS use different paradigms and I don't have assurance they'll work the same. If I'm wrong here, please don't hesitate to burn me at the stake.
Extra info, disregard if you'd like:
I've already RTFM, and the wording and examples suggest I can't do the above with map
. The MDN docs describe map
as "calling a provided function on every element in an array", while the MSDN docs say it "calls a function on each element of an array, and returns an array." I'm not trying to call a method on an array, I'm trying to call a method from several context objects. If this is not possible, is there a native polyfill?
I'm using this in a game, so speed is my main concern. If there is a more optimal way to code this, please let me know!
TL;DR: Basically, I'm trying to use Array.prototype.map()
to call a method mon to a list of context objects.
Say I have some code like this:
a.doSomething();
b.doSomething();
c.doSomething();
d.doSomething();
e.doSomething();
...
This is overly verbose. I want to be able to shorten this code up to something like this
[a, b, c, d, e].map(doSomething);
because I don't want to have to use a for
loop.
How would I be able to do this with the native map
function in JS, without any external libraries?
Thank you in advance! If this post is too long, I will happily edit it. Just scream at me.
Related questions:
How to use map() to call class methods on a list of objects
How to call same method for a list of objects?
I didn't use the info in the related questions because Python and JS use different paradigms and I don't have assurance they'll work the same. If I'm wrong here, please don't hesitate to burn me at the stake.
Extra info, disregard if you'd like:
I've already RTFM, and the wording and examples suggest I can't do the above with map
. The MDN docs describe map
as "calling a provided function on every element in an array", while the MSDN docs say it "calls a function on each element of an array, and returns an array." I'm not trying to call a method on an array, I'm trying to call a method from several context objects. If this is not possible, is there a native polyfill?
I'm using this in a game, so speed is my main concern. If there is a more optimal way to code this, please let me know!
Share Improve this question edited May 23, 2017 at 12:29 CommunityBot 11 silver badge asked Jul 26, 2015 at 2:57 Dylan LaCoursiereDylan LaCoursiere 4791 gold badge8 silver badges18 bronze badges4 Answers
Reset to default 3The closest I can think of is
[a, b, c, d, e].forEach(function(item) {item.doSomething()});
using [].map would be pointless for your purpose
edit, you could also do something like this
Array.prototype.fnName = function(methodName) {
var args = Array.prototype.slice.call(arguments, 1);
this.forEach(function(item) {
item[methodName].apply(item, args);
});
};
I've used fnName
, you could call it fnMap
or something else that makes sense to you
you'd use it like
[a,b,c].fnName('doSomething', param1, param2 ...)
Replied without thinking. Array#map
is supported in most browsers today and was apart of ES5. See the MDN link: https://developer.mozilla/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
[1,2,3,4,5].map(function(item){ console.log(item)}
will print:
1
2
3
4
5
and return undefined. If you return something like:
[1,2,3,4,5].map(function(item){return 2*item})
it will return:
[2,4,6,8,10]
But it's not neccessary to return anything. You can just as easily do a forEach.
items.forEach(function(item){items.method()}
It's all O(n) time, because to apply anything to n items in the array, it takes at least n time. For loop is as good as it gets.
WRONG
ES6 supports #map
but it's not available on all browsers/Node.js without different settings being set.
Underscorejs has this functionality, if you do want an external library. See their map documentation: http://underscorejs/#map
I use it in server code, no problem. Should probably work for your game. If page load time is an issue, you can always extend the prototype of Array
yourself.
Array.map()
calls given function for every item in array. That’s where anonymous functions can be very appropriate:
[a, b, c].map(function (item) { item.doSomething(); });
Seeing this post is pretty old, I wanted to give some elements that might plement the other answers.
Let's take a simple class A
which has a method double
.
class A {
constructor(n) { this.n = n; }
double() { return 2 * this.n; }
}
We will have an array of instances to work on.
const data = [ new A(3), new A(12), new A(4), new A(10) ];
Function wrapper
The Array#map()
method takes in a function callback that it will execute on each of the elements of that array.
Essentially it es down to wrapping the method call on the object. To do so we can use a standard function like:
data.map(function(o) { return o.double() });
Usually however you would e across an arrow function instead:
data.map(o => o.double());
which alleviates the need for parentheses, curly braces and the return
statement.
Destructuring
Now we could try to improve this. We can actually destructure objects in the function's header. Below, we are retrieving double directly from the object and calling it:
data.map(({ double }) => double());
However, that won't work...
TypeError:
this
isundefined
What happens is, we are not calling double
on the current object. This is because of function binding, when independently calling double
as a function we are leaving the value of this
unset.
We could bind the function to the object,
data.map((o, _, __, fn=o.double) => fn.bind(o)())
but... this would defeat the purpose of going after a shorter version.
Class member arrow functions!
However, there is a way around this by using class member arrow functions.
class A {
constructor(n) { this.n = n; }
double = () => { return 2 * this.n; }
}
This way we bypass the need for a bind when calling the method.
Then we can successfully do:
data.map(({ double } => double());
Keep in mind, this is not supported by all browsers. And since you will have to fiddle with your class declarations in order to use this syntax sugar. I wouldn't really remend it. Class member arrow functions are quite nice for event handlers though...
Demo:
class A {
constructor(n) { this.n = n; }
double() { return 2 * this.n; }
triple = () => { return 3 * this.n; }
}
const data = [new A(3), new A(12), new A(4), new A(10)];
console.log(data.map(o => o.double()));
// console.log(data.map(({ double }) => double())); // won't work!
console.log(data.map((o, _,__, fn=o.double) => fn.bind(o)())); // ugly
console.log(data.map(({triple}) => triple()));