javascript - sirve - ¿Por qué parseInt produce NaN con Array#map?
parseint typescript (7)
Desde la Red de Desarrolladores de Mozilla :
[1,4,9].map(Math.sqrt)
rendirá:
[1,2,3]
¿Por qué entonces esto:
[''1'',''2'',''3''].map(parseInt)
ceder esto:
[1, NaN, NaN]
He probado en Firefox 3.0.1 y Chrome 0.3 y solo como una exención de responsabilidad, sé que esto no es una funcionalidad de navegador cruzado (no IE).
Descubrí que lo siguiente logrará el efecto deseado. Sin embargo, todavía no explica el comportamiento errante de parseInt
.
[''1'',''2'',''3''].map(function(i){return +i;}) // returns [1,2,3]
La función de devolución de llamada en Array.map
tiene tres parámetros:
Desde la misma página de Mozilla a la que has vinculado:
la devolución de llamada se invoca con tres argumentos: el valor del elemento, el índice del elemento y el objeto de la matriz que se está atravesando ".
Entonces, si llama a una función parseInt
que realmente espera dos argumentos, el segundo argumento será el índice del elemento.
En este caso, terminó llamando a parseInt
con radix 0, 1 y 2 sucesivamente. El primero es el mismo que no proporciona el parámetro, por lo que se basa en la entrada (base 10, en este caso). Base 1 es una base numérica imposible, y 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 de envoltura:
[''1'',''2'',''3''].map(function(num) { return parseInt(num, 10); });
o con la sintaxis ES2015 +:
[''1'',''2'',''3''].map(num => parseInt(num, 10));
(En ambos casos, es mejor proporcionar explícitamente un radix para parseInt
como se muestra, porque de lo contrario adivina el radix en función de la entrada. En algunos navegadores más antiguos, un 0 inicial hizo que adivinara el octal, que solía ser problemático. todavía adivinar hexadecimal si la cadena comienza con 0x
.)
Puede utilizar la función de flecha ES2015 / ES6 y simplemente pasar el número al parseInt. El valor predeterminado para radix será 10
[10, 20, 30].map(x => parseInt(x))
O puede especificar explícitamente radix para una mejor legibilidad de su código.
[10, 20, 30].map(x => parseInt(x, 10))
En el ejemplo anterior, radix se establece explícitamente en 10
Puedes resolver este problema usando la función de Number como iterador:
var a = [''0'', ''1'', ''2'', ''10'', ''15'', ''57''].map(Number);
console.log(a);
Sin el nuevo operador, se puede usar Número para realizar la conversión de tipo. 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"));
Voy a apostar a que está pasando algo raro con el segundo parámetro de parseInt, el radix. Por qué se está rompiendo 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 ) } );
otra solución rápida (de trabajo):
var parseInt10 = function(x){return parseInt(x, 10);}
[''0'', ''1'', ''2'', ''10'', ''15'', ''57''].map(parseInt10);
//[0, 1, 2, 10, 15, 57]
map
pasa a lo largo de un segundo argumento, que (en muchos de los casos) parseInt
el parámetro radix de parseInt
.
Si estás usando guión bajo puedes hacer:
[''10'',''1'',''100''].map(_.partial(parseInt, _, 10))
O sin subrayar:
[''10'',''1'',''100''].map(function(x) { return parseInt(x, 10); });
parseInt
IMHO debe evitarse por esta misma razón. Puede envolverlo para hacerlo más seguro en estos contextos como este:
const safe = {
parseInt: (s, opt) => {
const { radix = 10 } = opt ? opt : {};
return parseInt(s, radix);
}
}
console.log( [''1'',''2'',''3''].map(safe.parseInt) );
console.log(
[''1'', ''10'', ''11''].map(e => safe.parseInt(e, { radix: 2 }))
);
lodash / fp encapsula los argumentos iterativos a 1 por defecto para evitar estos errores. Personalmente, he encontrado estas soluciones para crear tantos errores como evitan. La parseInt
en parseInt
a favor de una implementación más segura es, creo, un mejor enfoque.