Why doesn't the following work? (Chrome, so no issues with Arrays.map missing)
[" a ", "b", " c", "d "].map(String.prototype.trim)
TypeError: String.prototype.trim called on null or undefined
map passes each element of the array as parameter to the function:
[element1, e2].map(myFunction); // --> myFunction(element1); myFunction(e2)
String.prototype.trim is not a function that you pass a string to be trimmed. You call the function as a method of that string, instead:
" some string ".trim(); // "some string"
To use trim in a .map, you'll need to do something like:
[" a ", "b", " c", "d "].map(e => e.trim());
this works.[" a ", "b", " c", "d "]
.map(Function.prototype.call.bind(String.prototype.trim))
or
[" a ", "b", " c", "d "].map(fetch.call.bind("".trim))
// .map(<a whatever function>.call.bind(<a whatever string>.trim))
or simply
[" a ", "b", " c", "d "].map(s => s.trim())
.
….map(String.prototype.trim)?Because the trim function trims this, not its argument. It does not have any parameters. You do " no ".trim() (" no " being the this), not trim(" no ").
….map(String.prototype.trim.call) when the call forwards the first argument as this?Because, in this example, the function which the call function forwards to, is not String.prototype.trim, but undefined. The call function forwards to its this, and in this example, the call function is called without this, as if you do (undefined).call(…).
This example is the same as doing:
const _call = String.prototype.trim.call;
// _call has no `this`.
….map(_call)
and in this case, the _call function’s this is not String.prototype.trim, unlike the direct call String.prototype.trim.call(…) (in the form of <this>.<function>()). The _call variable is a mere function value that does not retain String.prototype.trim as its this.
For the call function to retain String.prototype.trim as its default this, you need to use the Function.prototype.bind function to bind the specific this, String.prototype.trim, to it. The bind function also forwards arguments.
const call_without_this = Function.prototype.call;
const trim_without_this = String.prototype.trim;
const call_with_trim_as_its_this =
call_without_this.bind(trim_without_this);
….map(call_with_trim_as_its_this)
The function returned by the bind function call, call_with_trim_as_its_this, is a function that calls the call function with this of trim_without_this and arguments being forwarded, that is, a function that calls trim_without_this with this of the first argument.
And also, since properties in the prototype of a class are inherited by instances of the class, <class>.prototype.<property> can be replaced with <the class’ instance>.<property>.
const call_without_this = fetch.call;
const trim_without_this = "".trim;
const call_with_trim_as_its_this =
call_without_this.bind(trim_without_this);
….map(call_with_trim_as_its_this)
With Ramda (functional programming library for Javascript):
> var R = require('ramda')
undefined
> [" a ", "b", " c", "d "].map(R.trim)
[ 'a', 'b', 'c', 'd' ]
This example was made using the built-in node repl.
map()will pass the element as a parameter to the callback andtrim()has to be called as a method of some string-object (no parameter).String.prototype.trim.call(" x ")works, but why not[" x "].map(String.prototype.trim.cal)ldoesn't?