Reputation: 16515
I was wondering if it was possible to pass an instance method into the Array.prototype.map function.
for example, I basically want this functionality without having to make a separate function
function Node(n) {
this.val = n;
}
Node.prototype.isBig = function() {
return this.val > 5;
}
var myArray = [
new Node(1), new Node(2), new Node(3),
new Node(7), new Node(8), new Node(9)
];
console.log(myArray);
var result = myArray.map(function(node) {
return node.isBig();
});
console.log(result);
in java I would be able to do .map(Node::isBig)
. Can I do something to change the map parameter so that I don't have to create a function?
I am also open to solutions with lodash if you cannot do it with vanilla js.
Upvotes: 2
Views: 1356
Reputation: 92274
You'd have to create a function that takes node as its parameter (that is, it doesn't rely on this
Node.isBig = function(node) {
return node.isBig();
};
//works because function doesn't depend on this
myArray.map(Node.isBig);
// doesn't work, depends on this
myArray.map(Node.prototype.isBig);
Alternatively, you could create a function that returns another function that takes its first parameter and calls it as this
function passFirstArgAsThis (fun) {
return function() {
fun.apply(arguments[0], arguments);
}
}
myArray.map( passFirstArgAsThis(Node.prototype.isBig));
A slightly more cryptic implementation is
function passFirstArgAsThis(fn) {
return function() {
return fn.call.apply(fn, arguments);
};
}
The equivalent in ES6 is more readable
function passFirstArgAsThis(fn) {
return function() {
// arguments[0] will be the first argument passed to call
// map will pass it as the node, we will make it become `this`
// when calling the passed in function
return fn.call(...arguments);
};
}
Understanding that, Oriol's answer becomes easier to comprehend
function passFirstArgAsThis(fn) {
// we return a bound function that will execute the call method, bound
// to the same passed in function
return fn.call.bind(fn);
// Same as
// return function() {
// return fn.call(...arguments);
// }
}
Personally, I would use fat arrow functions for readability, and not needing an extra "static" function.
nodes.map(n=>n.isBig())
Upvotes: 1
Reputation: 288020
I don't think you can do it strictly without creating new functions, but you can avoid function expressions and declarations by binding existing functions to some value.
For example, you can use Function.prototype.call
to call Node.prototype.isBig
with the appropriate this
value.
var result = myArray.map(Function.prototype.call.bind(Node.prototype.isBig));
There is also a proposal of a bind operator, which I think it would allow
var result = myArray.map(::Node.prototype.isBig.call);
Note additional arguments (index and array) will be passed to the isBig
method.
function Node(n) {
this.val = n;
}
Node.prototype.isBig = function() {
return this.val > 5;
};
var myArray = [
new Node(1), new Node(2), new Node(3),
new Node(7), new Node(8), new Node(9)
];
var result = myArray.map(Function.prototype.call.bind(Node.prototype.isBig));
document.write(JSON.stringify(result));
And in ES6, you can consider using arrow functions:
var result = myArray.map(node => node.isBig());
Upvotes: 4