Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

javascript

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.

like image 427
alex Avatar asked Feb 16 '12 00:02

alex


4 Answers

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

like image 118
Mrchief Avatar answered Sep 27 '22 04:09

Mrchief


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();
});
like image 27
Thomas Eding Avatar answered Sep 27 '22 04:09

Thomas Eding


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.

like image 36
Aaron Powell Avatar answered Oct 01 '22 04:10

Aaron Powell


With ES6 syntax it can be as easy as this:

[' hello  ', '  world'].map(str => str.trim());
like image 22
mahdavipanah Avatar answered Sep 30 '22 04:09

mahdavipanah