Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass the method defined on prototype to Array.map as callback

I have an array

var arr = [' A ', ' b ', 'c'];

and I want to trim the spaces from each of the element from array.

It can be done by using Array.map as

arr.map(function(el) {
    return el.trim();
});

I'm curious about passing the trim/toLowerCase function directly to the map as callback function, like arr.map(Math.max.apply.bind(Math.max, null)); to get the maximum element from each subarray or arr.map(Number); to cast each element to Number.

I've tried

arr.map(String.prototype.trim.apply);

but it is throwing error

Uncaught TypeError: Function.prototype.apply was called on undefined, which is a undefined and not a function

I expect that String.prototype.trim.apply should be called for each element in the array with the context set to the element from array(passed to apply);

I've also tried different combinations of apply, call and bind with no success.

  1. Why the function on prototype cannot be referenced when using map
  2. How function can be passed as parameter to map
like image 873
Tushar Avatar asked Oct 08 '15 03:10

Tushar


1 Answers

arr.map(String.prototype.trim.call.bind(String.prototype.trim));

call uses this internally, which must point to the trim function to work properly in this case. Simply passing String.prototype.trim.call would leave call unbound to any method, resulting in the this value pointing to window instead.

It works, but when used apply instead of call it throws error, arr.map(String.prototype.trim.apply.bind(String.prototype.trim));

The problem is that map will pass 2 arguments, the item and the index. Therefore it ends up calling something like 'String.prototype.trim.apply('test', 0) which fails since the second argument must be an array.

one more thing [' A ', ' B ', 'c'].map(String.prototype.trim.call.bind(String.prototype.toLowerCase));, in this, I've used trim.call and passed toLowerCase as context then why we need trim here, why trim is not called

When using call.bind the path that you chose to access the call function reference becomes irrelevant. The function that will get called is the one that is bound.

If you want to compose functions together you will need a different approach:

var call = Function.prototype.call,
    trim = call.bind(String.prototype.trim),
    toLowerCase = call.bind(String.prototype.toLowerCase),
    trimAndLowerCase = pipelineFrom(trim, toLowerCase);

[' TeST '].map(trimAndLowerCase);

function pipelineFrom(fn1, fn2) {
    return function (val) {
        return fn2(fn1(val));
    };
}

However at this point you're better off with:

arr.map(function (val) {
    return val.trim().toLowerCase();
});
like image 200
plalx Avatar answered Sep 30 '22 17:09

plalx