16

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
3
  • 2
    The problem is, that map() will pass the element as a parameter to the callback and trim() has to be called as a method of some string-object (no parameter). Commented Aug 6, 2014 at 13:59
  • String.prototype.trim.call(" x ") works, but why not [" x "].map(String.prototype.trim.cal)l doesn't? Commented Sep 21, 2021 at 21:21
  • @MichaelPacheco Check out my answer. Commented May 31, 2022 at 18:38

5 Answers 5

31

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());
Sign up to request clarification or add additional context in comments.

2 Comments

Or in ES6 it would be written like so: [" a ", "b", " c", "d "].map(e => e.trim())
All the .trim() fx on these answers are giving me "element.trim is not a function". What could cause that? --Solved. It because each of my elements is an array.
9

One shorter version with an arrow function:

[" a ", "b", " c", "d "].map(e => e.trim());

Comments

5

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();
});

Comments

4

Learn how this works.


Do either

[" 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())

.


Why not—

….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)

Comments

-2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.