alex
alex

Reputation: 490283

Why won't passing `''.trim()` straight to `[].map()`'s callback work?

I have an array of strings. I want to trim each string in the array.

I thought using [].map() with ''.trim() would work...

[' a', ' b   ', 'c'].map(String.prototype.trim);

...but my console said...

TypeError: String.prototype.trim called on null or undefined

jsFiddle.

I can't see any null or undefined values in my array.

String.prototype.trim() and Array.prototype.map() are defined in Chrome 17, which I'm using to test.

Why doesn't this work? I get the feeling I have overlooked something obvious.

I realise I could loop or drop a function in there. That's not the point of this question, however.

Upvotes: 25

Views: 7239

Answers (4)

Thomas Eding
Thomas Eding

Reputation: 1

That's because trim is not being called with the proper this context. Remember that this is dynamically bound in JS. You will have to create a wrapper to pass to trim to properly bind this:

[' a', ' b   ', 'c'].map(function (str) {
  return str.trim();
});

Upvotes: 25

mahdavipanah
mahdavipanah

Reputation: 600

With ES6 syntax it can be as easy as this:

[' hello  ', '  world'].map(str => str.trim());

Upvotes: 3

Mrchief
Mrchief

Reputation: 76218

What @Slace says is the right explanation. @ThomasEding's answer also works but has one terrible inefficieny that it may create functions within a loop, which is not a good thing to do.

Another way of doing would be (reference here):

[' a', ' b   ', 'c'].map(Function.prototype.call, String.prototype.trim);  
// gives ["a", "b", "c"]

Standard browser disclaimer: This will work wherever Function.prototype.call and String.prototype.trim will work and for older browsers, you can easily substitute trim with a polyfill like this:

if(!String.prototype.trim) {  
  String.prototype.trim = function () {  
    return this.replace(/^\s+|\s+$/g,'');  
  };  
}

Update: Interstingly, while this works fastest in Chrome, @ThomasEding's method runs slightly faster in IE10 and FF20 - http://jsperf.com/native-trim-vs-regex-trim-vs-mixed

Upvotes: 35

Aaron Powell
Aaron Powell

Reputation: 25097

trim is on the String prototype, meaning that it expects the this context to be that of a string where as the map method on Array provides the current array item as the first argument and the this context being the global object.

Upvotes: 20

Related Questions