2012-02-16 7 views
23

Tengo una serie de cadenas. Quiero recortar cada cuerda en la matriz.¿Por qué no pasar `` '.trim() `directamente al trabajo de devolución de llamada` [] .map() `?

pensé usando [].map() con ''.trim() funcionaría ...

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

... pero mi consola dijo ...

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

jsFiddle.

No puedo ver ningún null o undefined valores en mi matriz.

String.prototype.trim() y Array.prototype.map() se definen en Chrome 17, que estoy usando para probar.

¿Por qué no funciona? Tengo la sensación de haber pasado por alto algo obvio.

Me doy cuenta de que podría hacer un bucle o soltar una función allí. Sin embargo, ese no es el punto de esta pregunta.

Respuesta

16

trim está en el prototipo String, lo que significa que se espera que el contexto this a ser la de una cadena en la que el método map en Array proporciona el elemento de la matriz actual como el primer argumento y el contexto this ser el objeto global.

+0

! Sabía que sería algo obvio. Mi cerebro no está funcionando hoy. Gracias Slace. – alex

+2

Entonces, ¿por qué esto no funciona?'['a', 'b', 'c']. map (String.prototype.trim.apply);' ... y ¿por qué funciona esto fuera del contexto 'map()'? 'String.prototype.trim ('a')' (tenga en cuenta que en realidad * no funciona * - devuelve una cadena vacía - pero tampoco arroja un error). – nrabinowitz

+5

@nrabinowitz: 'apply''s' this' no se une a 'String.prototype.trim' - se enlaza a' undefined' o 'null' o' window'. (Esta es la razón por la que inventaron 'Function.bind()'.) – Ryan

25

Esto se debe a que trim no se está llamando con el contexto apropiado de this. Recuerde que this está enlazado dinámicamente en JS. Usted tendrá que crear un contenedor para pasar a trim para enlazar adecuadamente this:

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

Gracias por responder. Creo que he estado usando '$ .trim()' de jQuery con demasiada frecuencia. – alex

+0

¡Muy buena respuesta! :) – CoR

+0

Esto es casi perfecto, excepto por el hecho de que está creando funciones en un bucle. – Mrchief

30

Qué dice @Slace es la explicación correcta. @ La respuesta de ThomasEding también funciona, pero tiene una terrible ineficiencia que puede crear funciones dentro de un bucle, que es not a good thing to do.

Otra forma de hacerlo sería (reference here):

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

estándar descargo de responsabilidad navegador: Esto funcionará siempre que sea Function.prototype.call y String.prototype.trim va a funcionar y para exploradores más antiguos, se puede sustituir fácilmente trim con un polyfill como este:

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

Actualización: Interstingly, mientras que esto funciona más rápido en Chrome, @ método de ThomasEding corre un poco más rápido en IE10 y FF20 - http://jsperf.com/native-trim-vs-regex-trim-vs-mixed

+1

Estoy bastante seguro de que la respuesta de @ ThomasEdig no crea más de una función. Supongo que la función 'map' acepta una referencia de función y luego * la llama * una vez por iteración. La función en sí misma se crea una vez y luego * pasó a * la función 'map', al igual que la implementación de' map' de jQuery: http://james.padolsey.com/jquery/#v=1.7.2&fn=jQuery.map –

+0

Sí ... De mis pruebas, eso parece ser cierto. Haré las correcciones. – Mrchief

1

Con ES6 sintaxis puede ser tan fácil como esto:

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

Esta es la mejor manera de hacerlo en 2017. Veamos qué sucede en 2018: D –

Cuestiones relacionadas