Perché parseInt produce NaN con Array # map?


291

Dalla rete di sviluppatori Mozilla :

[1,4,9].map(Math.sqrt)

produrrà:

[1,2,3]

Perché allora fa questo:

['1','2','3'].map(parseInt)

cedere questo:

[1, NaN, NaN]

Ho testato in Firefox 3.0.1 e Chrome 0.3 e, proprio come disclaimer, so che questa non è funzionalità cross-browser (no IE).

Ho scoperto che quanto segue otterrà l'effetto desiderato. Tuttavia, non spiega ancora il comportamento errante di parseInt.

['1','2','3'].map(function(i){return +i;}) // returns [1,2,3]

15
Per i pigri: usare .map(parseFloat)perché richiede solo un parametro.

63
Oppure usa .map(Number).
Nikolai,

2
puoi arr.map (Math.floor) se vuoi Integer senza una funzione arrotolata a mano.
dandavis,

@Nikolai user669677 ottimi suggerimenti! Lo direi in una risposta
BiAiB il

qualcuno può spiegare perché parseInt analizza correttamente il primo numero e fa un errore diverso dal primo indice
bawa g

Risposte:


478

La funzione di callback in Array.mapha tre parametri:

Dalla stessa pagina Mozilla a cui hai collegato:

il callback viene invocato con tre argomenti: il valore dell'elemento, l'indice dell'elemento e l'oggetto Array attraversati. "

Quindi, se chiamate una funzione parseIntche prevede effettivamente due argomenti, il secondo argomento sarà l'indice dell'elemento.

In questo caso, hai finito per chiamare parseIntcon radix 0, 1 e 2 a turno. Il primo è lo stesso di non fornire il parametro, quindi è predefinito in base all'input (base 10, in questo caso). La base 1 è una base numerica impossibile e 3 non è un numero valido nella 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 

Quindi, in questo caso, è necessaria la funzione wrapper:

['1','2','3'].map(function(num) { return parseInt(num, 10); });

o con sintassi ES2015 +:

['1','2','3'].map(num => parseInt(num, 10));

(In entrambi i casi, è meglio fornire esplicitamente una radice parseIntcome mostrato, perché altrimenti indovina la radice in base all'input. In alcuni browser più vecchi, uno 0 iniziale lo induceva a indovinare ottale, che tendeva a essere problematico. indovina esadecimale se la stringa inizia con 0x.)


25

mapsta passando un secondo argomento, che (in molti casi) confonde il parseIntparametro radix.

Se stai usando la sottolineatura puoi fare:

['10','1','100'].map(_.partial(parseInt, _, 10))

O senza trattino basso:

['10','1','100'].map(function(x) { return parseInt(x, 10); });


18

È possibile risolvere questo problema utilizzando il numero come funzione ripetuta:

var a = ['0', '1', '2', '10', '15', '57'].map(Number);

console.log(a);

Senza il nuovo operatore, Numero può essere utilizzato per eseguire la conversione del tipo. Tuttavia, differisce da parseInt: non analizza la stringa e restituisce NaN se il numero non può essere convertito. Per esempio:

console.log(parseInt("19asdf"));
console.log(Number("19asf"));


11

Scommetto che è qualcosa di strano che sta succedendo con il secondo parametro di parseInt, il radix. Perché non si sta rompendo con l'uso di Array.map e non quando lo si chiama direttamente, non lo so.

//  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 ) } );

1
parseInt assume ottale solo se la stringa fornita inizia con un carattere 0.
Alnitak,

Oh ya ... esatto. Cerca di "indovinare" il radix in base all'input. Mi dispiace per quello.
Peter Bailey,

3

È possibile utilizzare la funzione freccia ES2015 / ES6 e passare semplicemente il numero al parseInt. Il valore predefinito per radix sarà 10

[10, 20, 30].map(x => parseInt(x))

Oppure puoi specificare esplicitamente radix per una migliore leggibilità del tuo codice.

[10, 20, 30].map(x => parseInt(x, 10))

Nell'esempio sopra radix impostato esplicitamente su 10


1

un'altra soluzione rapida (funzionante):

var parseInt10 = function(x){return parseInt(x, 10);}

['0', '1', '2', '10', '15', '57'].map(parseInt10);
//[0, 1, 2, 10, 15, 57]

0

parseIntIMHO dovrebbe essere evitato proprio per questo motivo. Puoi avvolgerlo per renderlo più sicuro in questi contesti come questo:

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 limita in modo predefinito gli argomenti a 1 per evitare questi trucchi. Personalmente ho trovato queste soluzioni alternative per creare tutti i bug che evitano. La lista nera parseInta favore di un'implementazione più sicura è, a mio avviso, un approccio migliore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.