Mengapa parseInt menghasilkan NaN dengan # peta Array?


291

Dari Jaringan Pengembang Mozilla :

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

akan menghasilkan:

[1,2,3]

Lalu mengapa melakukan ini:

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

hasilkan ini:

[1, NaN, NaN]

Saya telah menguji di Firefox 3.0.1 dan Chrome 0.3 dan hanya sebagai penafian, saya tahu ini bukan fungsi lintas-browser (tidak ada IE).

Saya menemukan bahwa yang berikut ini akan mencapai efek yang diinginkan. Namun, itu masih tidak menjelaskan perilaku bandel parseInt.

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

15
Untuk lazy: gunakan .map(parseFloat)karena hanya menggunakan satu parameter.

63
Atau gunakan .map(Number).
Nikolai

2
Anda dapat arr.map (Math.floor) jika Anda ingin Integer tanpa fungsi linting tangan.
Dandavis

@Nikolai user669677 saran bagus! Saya membenarkan hal itu di anwser
BiAiB

adakah yang bisa menjelaskan mengapa parseInt mem-parsing angka pertama dengan benar dan membuat kesalahan untuk selain indeks pertama
bawa g

Jawaban:


478

Fungsi panggilan balik di Array.mapmemiliki tiga parameter:

Dari halaman Mozilla yang sama dengan yang Anda tautkan:

callback dipanggil dengan tiga argumen: nilai elemen, indeks elemen, dan objek Array yang dilalui. "

Jadi jika Anda memanggil fungsi parseIntyang sebenarnya mengharapkan dua argumen, argumen kedua akan menjadi indeks elemen.

Dalam hal ini, Anda akhirnya memanggil parseIntdengan radix 0, 1 dan 2 secara bergantian. Yang pertama sama dengan tidak memasok parameter, sehingga default berdasarkan input (basis 10, dalam hal ini). Basis 1 adalah basis angka yang tidak mungkin, dan 3 bukan angka yang valid di basis 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 

Jadi dalam hal ini, Anda memerlukan fungsi wrapper:

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

atau dengan sintaks ES2015 +:

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

(Dalam kedua kasus, yang terbaik adalah secara eksplisit memasok radix parseIntseperti yang ditunjukkan, karena jika tidak menebak radix berdasarkan input. Pada beberapa browser yang lebih lama, 0 yang memimpin menyebabkannya menebak oktal, yang cenderung bermasalah. Itu masih akan bermasalah. tebak hex jika string dimulai dengan 0x.)


25

mapsedang menyampaikan argumen ke - 2, yang (dalam banyak kasus) mengacaukan parseIntparameter radix.

Jika Anda menggunakan garis bawah yang dapat Anda lakukan:

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

Atau tanpa garis bawah:

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


18

Anda bisa menyelesaikan masalah ini menggunakan Number as iteratee function:

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

console.log(a);

Tanpa operator baru, Number dapat digunakan untuk melakukan konversi tipe. Namun, ini berbeda dari parseInt: tidak mem-parsing string dan mengembalikan NaN jika jumlahnya tidak dapat dikonversi. Misalnya:

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


11

Saya akan bertaruh bahwa ini adalah sesuatu yang funky yang terjadi dengan parameter ke-2 parseInt, radix. Mengapa ini melanggar dengan penggunaan Array.map dan tidak ketika Anda menyebutnya secara langsung, saya tidak tahu.

//  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 hanya mengasumsikan oktal jika string yang disediakan dimulai dengan karakter 0.
Alnitak

Oh ya ... benar juga. Mencoba "menebak" radix berdasarkan input. Maaf soal itu.
Peter Bailey

3

Anda dapat menggunakan fungsi panah ES2015 / ES6 dan hanya meneruskan nomor ke parseInt. Nilai default untuk radix adalah 10

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

Atau Anda dapat secara eksplisit menentukan radix untuk keterbacaan kode yang lebih baik.

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

Dalam contoh di atas, radix secara eksplisit diatur ke 10


1

perbaikan cepat lain (yang berfungsi):

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

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

0

parseIntIMHO harus dihindari karena alasan ini. Anda dapat membungkusnya untuk membuatnya lebih aman dalam konteks ini seperti ini:

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 caps iteratee argumen ke 1 secara default untuk menghindari gotcha ini. Secara pribadi saya telah menemukan solusi untuk membuat bug sebanyak yang mereka hindari. Daftar hitam parseIntuntuk implementasi yang lebih aman, saya pikir, merupakan pendekatan yang lebih baik.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.