Reputation: 4730
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
Upvotes: 14
Views: 18482
Reputation: 72857
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());
Upvotes: 30
Reputation: 14809
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)
Upvotes: 3
Reputation: 4398
One shorter version with an arrow function:
[" a ", "b", " c", "d "].map(e => e.trim());
Upvotes: 9
Reputation: 156
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.
Upvotes: -2
Reputation: 5625
That's actually because Array.map()
function should have a currentElement
as an argument, while String.prototype.trim
doesn't take any arguments, therefore we can't call it that way.
So, you'll have to do it hard way:
[" a ", "b", " c", "d "].map(function(elem){
return elem.trim();
});
Upvotes: 5