Tại sao parseInt mang lại NaN với Array # map?


291

Từ Mạng nhà phát triển Mozilla :

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

sẽ mang lại:

[1,2,3]

Tại sao sau đó làm điều này:

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

mang lại điều này:

[1, NaN, NaN]

Tôi đã thử nghiệm trong Firefox 3.0.1 và Chrome 0.3 và chỉ là từ chối trách nhiệm, tôi biết đây không phải là chức năng trình duyệt chéo (không có IE).

Tôi phát hiện ra rằng những điều sau đây sẽ đạt được hiệu quả mong muốn. Tuy nhiên, nó vẫn không giải thích hành vi sai lầm của parseInt.

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

15
Đối với lazy: sử dụng .map(parseFloat)vì nó mất một tham số.

63
Hoặc sử dụng .map(Number).
Nikolai

2
bạn có thể Array.map (Math.floor) nếu bạn muốn Số nguyên mà không có chức năng cuộn tay.
dandavis

@Nikolai user669677 gợi ý tuyệt vời! Tôi muốn thông báo rằng trong một anwser
BiAiB

bất cứ ai cũng có thể giải thích tại sao parseInt phân tích chính xác số đầu tiên và gây ra lỗi cho chỉ số đầu tiên
bawa g

Câu trả lời:


478

Hàm gọi lại Array.mapba tham số:

Từ cùng một trang Mozilla mà bạn đã liên kết đến:

gọi lại được gọi với ba đối số: giá trị của phần tử, chỉ mục của phần tử và đối tượng Array được duyệt qua. "

Vì vậy, nếu bạn gọi một hàm parseIntthực sự mong đợi hai đối số, thì đối số thứ hai sẽ là chỉ mục của phần tử.

Trong trường hợp này, bạn đã kết thúc cuộc gọi parseIntvới cơ số 0, 1 và 2 lần lượt. Đầu tiên giống như không cung cấp tham số, vì vậy nó được mặc định dựa trên đầu vào (cơ sở 10, trong trường hợp này). Cơ sở 1 là cơ sở số không thể và 3 không phải là số hợp lệ trong cơ sở 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 

Vì vậy, trong trường hợp này, bạn cần chức năng bao bọc:

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

hoặc với cú pháp ES2015 +:

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

(Trong cả hai trường hợp, tốt nhất là cung cấp một cơ số rõ ràngparseInt như được hiển thị, bởi vì nếu không, nó đoán cơ số dựa trên đầu vào. Trong một số trình duyệt cũ hơn, số 0 dẫn đầu khiến nó đoán được bát phân, có xu hướng có vấn đề. đoán hex nếu chuỗi bắt đầu bằng 0x.)


25

mapđang chuyển qua một đối số thứ 2, trong đó (trong nhiều trường hợp) làm rối parseIntthông số cơ số của nó.

Nếu bạn đang sử dụng gạch dưới, bạn có thể làm:

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

Hoặc không có dấu gạch dưới:

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


18

Bạn có thể giải quyết vấn đề này bằng cách sử dụng hàm Number as iteratee:

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

console.log(a);

Không có toán tử mới, Số có thể được sử dụng để thực hiện chuyển đổi loại. Tuy nhiên, nó khác với parseInt: nó không phân tích chuỗi và trả về NaN nếu số này không thể được chuyển đổi. Ví dụ:

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


11

Tôi sẽ đặt cược rằng đó là một cái gì đó thú vị đang diễn ra với tham số thứ 2 của parseInt, cơ số. Tại sao nó lại vi phạm với việc sử dụng Array.map mà không phải khi bạn gọi nó trực tiếp, tôi không biết.

//  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 chỉ giả sử bát phân nếu chuỗi được cung cấp bắt đầu bằng 0 ký tự.
Alnitak

Oh ya ... đúng vậy. Nó cố gắng "đoán" cơ số dựa trên đầu vào. Xin lỗi vì điều đó.
Peter Bailey

3

Bạn có thể sử dụng chức năng mũi tên ES2015 / ES6 và chỉ cần chuyển số cho parseInt. Giá trị mặc định cho cơ số sẽ là 10

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

Hoặc bạn có thể chỉ định rõ ràng cơ số để dễ đọc mã hơn.

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

Trong ví dụ trên, cơ số rõ ràng được đặt thành 10


1

một cách khắc phục nhanh (đang hoạt động) khác:

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

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

0

parseIntIMHO nên tránh vì lý do này rất. Bạn có thể bọc nó để làm cho nó an toàn hơn trong những bối cảnh như thế này:

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 mũ iteratee đối số thành 1 theo mặc định để tránh các vấn đề này. Cá nhân tôi đã tìm thấy các cách giải quyết này để tạo ra nhiều lỗi như họ tránh. Danh sách đen parseIntủng hộ việc thực hiện an toàn hơn, tôi nghĩ, một cách tiếp cận tốt hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.