why `lodash.map(['A'], String.prototype.toLowerCase.call)` does not work?

If I want get an array of strings converted to lowercase, this seems like the normal thing to do:

lodash = require('lodash')
lodash.map(['A', 'B'], String.prototype.toLowerCase.call)

TypeError: object is not a function
    at Function.map (/Users/alejandro.carrasco/repos/cap-proxy/node_modules/lodash/dist/lodash.js:3508:27)
    at repl:1:9
    at REPLServer.self.eval (repl.js:110:21)
    at Interface.<anonymous> (repl.js:239:12)
    at Interface.EventEmitter.emit (events.js:95:17)
    at Interface._onLine (readline.js:202:10)
    at Interface._line (readline.js:531:8)
    at Interface._ttyWrite (readline.js:760:14)
    at ReadStream.onkeypress (readline.js:99:10)
    at ReadStream.EventEmitter.emit (events.js:98:17)

I've dug a little bit in the code and it seems that the problem is produced by the createCallback wrapping the passed function used inside map:

lodash.createCallback(String.prototype.toLowerCase.call)('A')

TypeError: object is not a function
    at repl:1:58
    at REPLServer.self.eval (repl.js:110:21)
    at Interface.<anonymous> (repl.js:239:12)
    at Interface.EventEmitter.emit (events.js:95:17)
    at Interface._onLine (readline.js:202:10)
    at Interface._line (readline.js:531:8)
    at Interface._ttyWrite (readline.js:760:14)
    at ReadStream.onkeypress (readline.js:99:10)
    at ReadStream.EventEmitter.emit (events.js:98:17)
    at emitKey (readline.js:1095:12)

But I don't really understand what's going on there...

I know that it works if I pass a callback like this:

function(x) {return x.toLowerCase()}

but the curiosity is killing me...

Why

The same reason ['A', 'B'].map(String.prototype.toLowerCase.call) is not working — it effectively uses Function.prototype.call.call(thisArg, currentValue) as an iterator which throws TypeError: object is not a function because your thisArg is global context (process) instead of String.prototype.toLowerCase.

How

// You expect this to be your iterator:
String.prototype.toLowerCase.call('A');

// Instead, you got this:
String.prototype.toLowerCase.call.call(thisArg, 'A');

Since thisArg is bound to process in your example, line above is pretty much the same as: process() with this bound to 'A'.

// The "correct" invocation "should" be:
String.prototype.toLowerCase.call.call(String.prototype.toLowerCase, 'A');

Fix

You can fix it by passing "correct" thisArg. The following ones work, but such maps do not look better than function(x) {return x.toLowerCase()} to me:

['A'].map(String.prototype.toLowerCase.call, String.prototype.toLowerCase);
['A'].map(String.prototype.toLowerCase.call.bind(String.prototype.toLowerCase));
['A'].map(Function.prototype.call, String.prototype.toLowerCase);
['A'].map(Function.prototype.call.bind(String.prototype.toLowerCase));

When you pass String.prototype.toLowerCase.call as the iterator function, you're really just passing the call function, without a context.

The context of the call function is usually the function which should be called. In this case it seems like the context is set to some object (global object?), and therefore you get the error object is not a function.

A possible solution is to bind the context of Function.call to String.prototype.toLowerCase, like so:

_.map(['A', 'B'], Function.call.bind(String.prototype.toLowerCase));

Or a bit shorter:

_.map(['A', 'B'], Function.call.bind("".toLowerCase));

After some more testing I found that the following code works with underscore but not with Lo-Dash, at least in the browser:

_.map(['A', 'B'], Function.call, "".toLowerCase);