¿Por qué parseInt produce NaN con Array#map?
De la red de desarrolladores de Mozilla :
[1,4,9].map(Math.sqrt)
rendirá:
[1,2,3]
¿Por qué entonces hace esto?
['1','2','3'].map(parseInt)
producir esto:
[1, NaN, NaN]
Lo he probado en Firefox 3.0.1 y Chrome 0.3 y, como descargo de responsabilidad, sé que esta no es una funcionalidad para varios navegadores (no IE).
Descubrí que lo siguiente logrará el efecto deseado. Sin embargo, todavía no explica el comportamiento errático de parseInt
.
['1','2','3'].map(function(i){return +i;}) // returns [1,2,3]
La función de devolución de llamada Array.map
tiene tres parámetros:
Desde la misma página de Mozilla a la que vinculó:
La devolución de llamada se invoca con tres argumentos: el valor del elemento, el índice del elemento y el objeto Array que se está atravesando".
Entonces, si llamas a una función parseInt
que realmente espera dos argumentos, el segundo argumento será el índice del elemento.
En este caso, terminaste igualando parseInt
con las bases 0, 1 y 2 por turno. El primero es lo mismo que no proporcionar el parámetro, por lo que se establece de forma predeterminada según la entrada (base 10, en este caso). La base 1 es una base numérica imposible y el 3 no es un número válido en base 2:
parseInt('1', 0); // OK - gives 1
parseInt('2', 1); // FAIL - 1 isn't a legal radix
parseInt('3', 2); // FAIL - 3 isn't legal in base 2
Entonces, en este caso, necesitas la función contenedora:
['1','2','3'].map(function(num) { return parseInt(num, 10); });
o con sintaxis ES2015+:
['1','2','3'].map(num => parseInt(num, 10));
(En ambos casos, es mejor proporcionar explícitamente una base parseInt
como se muestra, porque de lo contrario adivina la base en función de la entrada. En algunos navegadores más antiguos, un 0 inicial hacía que adivinara octal, lo que tendía a ser problemático. Aún así adivina hexadecimal si la cadena comienza con 0x
.)
map
está pasando un segundo argumento, que (en muchos de los casos) está arruinando parseInt
el parámetro de base de '.
Si estás usando un guión bajo, puedes hacer:
['10','1','100'].map(_.partial(parseInt, _, 10))
O sin guión bajo:
['10','1','100'].map(function(x) { return parseInt(x, 10); });
Podrías resolver este problema usando Número como función iterativa:
var a = ['0', '1', '2', '10', '15', '57'].map(Number);
console.log(a);
Sin el nuevo operador, Número se puede utilizar para realizar la conversión de tipos. Sin embargo, difiere de parseInt: no analiza la cadena y devuelve NaN si el número no se puede convertir. Por ejemplo:
console.log(parseInt("19asdf"));
console.log(Number("19asf"));
Apuesto a que algo extraño está sucediendo con el segundo parámetro de parseInt, la base. Por qué se rompe con el uso de Array.map y no cuando lo llamas directamente, no lo sé.
// Works fine
parseInt( 4 );
parseInt( 9 );
// Breaks! Why?
[1,4,9].map( parseInt );
// Fixes the problem
[1,4,9].map( function( num ){ return parseInt( num, 10 ) } );
Puede usar la función de flecha ES2015/ES6 y simplemente pasar el número a parseInt. El valor predeterminado para radix será 10
[10, 20, 30].map(x => parseInt(x))
O puede especificar explícitamente la base para una mejor legibilidad de su código.
[10, 20, 30].map(x => parseInt(x, 10))
En el ejemplo anterior, la base se establece explícitamente en 10