2012-01-15 8 views
7

¿Por quéllamada [] .reverse en una cadena

[].reverse.call("string"); 

falla (error tanto en Firefox e IE, devuelve la cadena original en cromo), mientras que llamando a todos los otros métodos de matrices en una obra de cuerdas?

>>> [].splice.call("string",3) 
["i", "n", "g"] 
>>> [].map.call("string",function (a) {return a +a;}) 
["ss", "tt", "rr", "ii", "nn", "gg"] 
+0

_ "todos los otros métodos de matriz" _ - does '.sort()' work? Para los que sí funcionan, ¿funcionan en todos los navegadores? (Supongo que fallarían en navegadores más antiguos que no hayan implementado la notación de índice '[]' estilo de matriz para cadenas, aunque no lo he probado.) – nnnnnn

+0

@nnnnnn la ordenación no funciona por el mismo motivo – Hai

+0

@Hai: FYI, '.splice()' no funciona realmente. Chrome tiene la amabilidad de proporcionarle el valor devuelto, pero si hace referencia a la cadena original antes de empalmarla, verá que no se ha modificado. –

Respuesta

8

Debido .reverse() modifica una matriz, y las cadenas son inmutables.


Usted puede pedir prestado Array.prototype.slice para convertir a una matriz, entonces marcha atrás y unirse a ella.

var s = "string"; 

var s2 = [].slice.call(s).reverse().join(''); 

Tenga en cuenta que en las versiones anteriores de IE, no puede manipular una cadena como una matriz.

+1

Bien hecho - la brevedad es el alma del ingenio –

+1

@AdamRackis: Gracias, pero ahora me he ido y arruiné tu complemento. :) –

+0

@amnotiam, ya es demasiado tarde, lo siento. – OnTheFly

4

Consulte la respuesta de @am not i am para saber por qué no funciona. Sin embargo, si usted quiere saber cómo lograr esto, convertirlo en una matriz primero:

"string".split('').reverse().join(''); // "gnirts" 
+0

+1 '.split()' será una conversión de matriz más compatible con el navegador que '[] .slice()'. –

5

La técnica siguiente (o similar) se utiliza comúnmente para revertir una cadena en JavaScript:

// Don’t use this! 
var naiveReverse = function(string) { 
    return string.split('').reverse().join(''); 
} 

De hecho, todas las respuestas publicadas hasta ahora son una variación de este patrón. Sin embargo, hay algunos problemas con esta solución. Por ejemplo:

naiveReverse('foo bar'); 
// → 'rab �� oof' 
// Where did the `` symbol go? Whoops! 

Si usted se pregunta por qué sucede esto, read up on JavaScript’s internal character encoding. (TL; DR:. es un símbolo astral y JavaScript expone como dos unidades de código separadas)

Pero hay más:

// To see which symbols are being used here, check: 
// http://mothereff.in/js-escapes#1ma%C3%B1ana%20man%CC%83ana 
naiveReverse('mañana mañana'); 
// → 'anãnam anañam' 
// Wait, so now the tilde is applied to the `a` instead of the `n`? WAT. 

Una buena prueba de la cadena cadena de implementaciones inversa es the following:

'foo bar mañana mañana' 

¿Por qué? Porque contiene un símbolo astral () (que son represented by surrogate pairs in JavaScript) y una marca de combinación ( en el último mañana en realidad consta de dos símbolos: U + 006E LETRA PEQUEÑA LATINA N y U + 0303 COMBINANDO TILDE).

El orden en que aparecen los pares suplentes no se puede invertir, de lo contrario el símbolo astral no se mostrará más en la cadena 'invertida'. Es por eso que vio esas marcas �� en la salida del ejemplo anterior.

Las marcas de combinación siempre se aplican al símbolo anterior, por lo que debe tratar el símbolo principal (U + 006E LETRA PEQUEÑA LATINA N) como la marca de combinación (U + 0303 COMBINAR TILDE) como un todo. Invertir su orden hará que la marca de combinación se empareje con otro símbolo en la cadena. Es por eso que la salida de ejemplo tenía en lugar de ñ.

Afortunadamente, esto explica por qué todas las respuestas publicadas hasta ahora son mal.


Para responder a su pregunta inicial - cómo [adecuadamente] revertir una cadena en JavaScript -, he escrito una pequeña biblioteca JavaScript que es capaz de reversión cadena Unicode-aware. No tiene ninguno de los problemas que acabo de mencionar. La biblioteca se llama Esrever; su código está en GitHub, y funciona en prácticamente cualquier entorno de JavaScript. Viene con una utilidad/binario de shell, por lo que puede invertir cadenas fácilmente desde su terminal si lo desea.

var input = 'foo bar mañana mañana'; 
esrever.reverse(input); 
// → 'anañam anañam rab oof'