Tại sao isNaN (null) == false trong JS?


128

Mã này trong JS cung cấp cho tôi một cửa sổ bật lên nói rằng "tôi nghĩ null là một con số", mà tôi thấy hơi đáng lo ngại. Tôi đang thiếu gì?

if (isNaN(null)) {
  alert("null is not a number");
} else {
  alert("i think null is a number");
}

Tôi đang sử dụng Firefox 3. Đó có phải là lỗi trình duyệt không?

Các xét nghiệm khác:

console.log(null == NaN);   // false
console.log(isNaN("text")); // true
console.log(NaN == "text"); // false

Vì vậy, vấn đề dường như không phải là một so sánh chính xác với NaN?

Chỉnh sửa: Bây giờ câu hỏi đã được trả lời, tôi đã dọn sạch bài đăng của mình để có phiên bản tốt hơn cho kho lưu trữ. Tuy nhiên, điều này làm cho một số ý kiến ​​và thậm chí một số câu trả lời hơi khó hiểu. Đừng đổ lỗi cho tác giả của họ. Trong số những điều tôi đã thay đổi là:

  • Xóa một ghi chú nói rằng tôi đã làm hỏng tiêu đề ở nơi đầu tiên bằng cách hoàn nguyên ý nghĩa của nó
  • Các câu trả lời trước đó cho thấy rằng tôi không nói rõ đủ lý do tại sao tôi nghĩ hành vi đó là lạ, vì vậy tôi đã thêm các ví dụ kiểm tra chuỗi và thực hiện so sánh thủ công.

3
không phải bạn có nghĩa là "Tại sao isNaN (null) == false"?
Matt Rogish

Dựa trên mã của bạn, isnan (null) đang trả về false (null không phải là "không phải là số") nếu nó nói "Tôi nghĩ null là một số".
devinmoore

Câu trả lời:


114

Tôi tin rằng mã đang cố gắng hỏi, "là xsố?" với trường hợp cụ thể ở đây x = null. Hàm này isNaN()có thể được sử dụng để trả lời câu hỏi này, nhưng về mặt ngữ nghĩa, nó đề cập cụ thể đến giá trị NaN. Từ Wikipedia cho NaN:

NaN ( N ot a N umber) là một giá trị của kiểu dữ liệu số đại diện cho một giá trị không xác định hoặc không thể biểu thị, đặc biệt là trong các phép tính dấu phẩy động.

Trong hầu hết các trường hợp, chúng tôi nghĩ rằng câu trả lời cho "là null số?" nên là không Tuy nhiên, isNaN(null) == falselà đúng về mặt ngữ nghĩa, bởi vì nullkhông NaN.

Đây là lời giải thích thuật toán:

Hàm isNaN(x)cố gắng chuyển đổi tham số đã truyền thành số 1 (tương đương Number(x)) và sau đó kiểm tra xem giá trị có phải không NaN. Nếu tham số không thể được chuyển đổi thành một số, Number(x)sẽ trả về NaN2 . Do đó, nếu việc chuyển đổi tham số xthành một số kết quả NaN, nó sẽ trả về true; mặt khác, nó trả về false.

Vì vậy, trong trường hợp cụ thể x = null, nullđược chuyển đổi thành số 0, (thử đánh giá Number(null)và thấy rằng nó trả về 0,) và isNaN(0)trả về false. Một chuỗi chỉ có các chữ số có thể được chuyển đổi thành một số và isNaN cũng trả về sai. Một chuỗi (ví dụ 'abcd') không thể được chuyển đổi thành một số sẽ khiến isNaN('abcd')trả về true, cụ thể là vì Number('abcd')trả về NaN.

Ngoài các trường hợp cạnh rõ ràng này là các lý do số chuẩn để trả về NaN như 0/0.

Đối với các bài kiểm tra dường như không nhất quán về sự bình đẳng được hiển thị trong câu hỏi, hành vi của NaNđược chỉ định sao cho mọi so sánh x == NaNlà sai, bất kể toán hạng khác, bao gồm NaNchính nó 1 .


8
BTW NaN !== NaN,. Vì vậy, tôi nghĩ, nó không phải là hoàn toàn đúng khi nói Number('abcd') == NaNNumber('abcd')NaNnhưng không bằng NaN. Tôi ngưỡng mộ JavaScript.
nilfalse

Đúng. Tôi có nghĩa là để truyền đạt mà Number('abcd')NaNnhưng tôi ngụ ý rằng nó kiểm tra đúng đối với bình đẳng, mà không phải là trường hợp. Tôi sẽ chỉnh sửa nó.
Glenn Moss

Tôi tự hỏi tại sao isNaNNumberđược thiết kế để hành xử theo cách đó?
nhút nhát

1
Việc chuyển đổi nullthành 0chỉ (ít nhất là trong bối cảnh này) xảy ra trong isNaN()hàm, điều này ép buộc đối số của nó.
Glenn Moss

3
Số (null) == 0 nhưng parseInt (null) == NaN yêu JS
JoshBerke

31

Tôi chỉ chạy vào vấn đề này bản thân mình.

Đối với tôi, cách tốt nhất để sử dụng isNaN là như vậy

isNaN(parseInt(myInt))

lấy ví dụ của phyzome từ trên cao,

var x = [undefined, NaN,     'blah', 0/0,  null, 0,     '0',   1,     1/0, -1/0,  Number(5)]
x.map( function(n){ return isNaN(parseInt(n))})
        [true,      true,    true,   true, true, false, false, false, true, true, false]

(Tôi căn chỉnh kết quả theo đầu vào, hy vọng nó giúp đọc dễ dàng hơn.)

Điều này có vẻ tốt hơn với tôi.


1
Sẽ không hoạt động nếu myInt= "123d". parseIntchuyển đổi "123d" thành 123, sau đó thất bại trong isNaNbài kiểm tra.
divesh ra mắt

thật vậy, nếu bạn cũng muốn nắm bắt kịch bản đó, tôi đề nghị kết hợp câu trả lời của tôi và Glenn. Nó sẽ trông như thế này isNaN(parseInt(str,10)) || isNaN(Number()). btw - đối với tôi, vì tôi phải chạy parseIntđể sử dụng giá trị số của chuỗi, cho phép "123d" được coi là số hợp lệ là ổn. Tuy nhiên tôi thấy sự cần thiết phải phát hiện kịch bản đó là tốt.
anh chàng mograbi

8

(Nhận xét khác của tôi có một cách tiếp cận thực tế. Đây là khía cạnh lý thuyết.)

Tôi đã tra cứu tiêu chuẩn ECMA 262 , đó là những gì Javascript thực hiện. Đặc điểm kỹ thuật của họ cho isNan:

Áp dụng ToNumber cho đối số của nó, sau đó trả về true nếu kết quả là NaN và nếu không thì trả về false.

Mục 9.3 chỉ định hành vi của ToNumber(không phải là chức năng có thể gọi được, mà là một thành phần của hệ thống chuyển đổi loại). Để tóm tắt bảng, một số loại đầu vào nhất định có thể tạo ra NaN. Đây là loại undefined, loại number(nhưng chỉ là giá trị NaN), bất kỳ đối tượng nào có biểu diễn nguyên thủy NaNvà bất kỳ đối tượng nào stringkhông thể được phân tích cú pháp. Lá này undefined, NaN, new Number(NaN), và hầu hết các chuỗi.

Bất kỳ đầu vào nào tạo ra NaNnhư một đầu ra khi được truyền vào ToNumbersẽ tạo ra một truekhi được cung cấp cho isNaN. Vì nullcó thể chuyển đổi thành số thành công, nó không tạo ra true.

Và đó là lý do tại sao.


7

Điều này thực sự đáng lo ngại. Đây là một loạt các giá trị mà tôi đã thử nghiệm:

var x = [undefined, NaN, 'blah', 0/0, null, 0, '0', 1, 1/0, -1/0, Number(5)]

Nó đánh giá (trong bảng điều khiển Fireorms) để:

,NaN,blah,NaN,,0,0,1,Infinity,-Infinity,5

Khi tôi gọi x.map(isNaN)(để gọi isNaN trên mỗi giá trị), tôi nhận được:

true,true,true,true,false,false,false,false,false,false,false

Tóm lại, isNaNtrông khá vô dụng! ( Chỉnh sửa : Ngoại trừ hóa ra isNaN chỉ được xác định trên Số, trong trường hợp đó, nó hoạt động tốt - chỉ với một tên gây hiểu lầm.)

Ngẫu nhiên, đây là các loại của các giá trị đó:

x.map(function(n){return typeof n})
-> undefined,number,string,number,object,number,string,number,number,number,number

Bạn tưởng tượng rằng NaN nên có nghĩa là gì? Bạn nghĩ gì là sai lệch về NaN hoặc trong thử nghiệm cho nó? Tại sao bạn lại băn khoăn?
Bekim Bacaj

Chà, điều này đã xảy ra cách đây 8 năm, nhưng có vẻ như tôi đã băn khoăn rằng 1) nó có kết quả không nhất quán đối với các giá trị không thuộc loại Số và 2) nó trở lại đúng với thứ không thuộc loại Số. Bởi vì trên thực tế, một chuỗi không phải là NaN. (Cũng xem câu trả lời khác của tôi, giải thích lý do tại sao điều này xảy ra.)
đối xử tốt với các mod của bạn vào

5

Null không phải là NaN, cũng như một chuỗi không phải là NaN. isNaN () chỉ kiểm tra nếu bạn thực sự có đối tượng NaN.


Nhưng sau đó, ít nhất một chuỗi được truyền vào một đối tượng NaN, vì isNaN ("văn bản") trả về đúng.
Hanno Fietz

1

Tôi không chắc chắn chính xác khi nói đến JS nhưng tôi đã thấy những điều tương tự trong các ngôn ngữ khác và điều đó thường là do hàm chỉ kiểm tra xem null có chính xác bằng NaN hay không (tức là null === NaN sẽ sai). Nói cách khác, không phải nó nghĩ rằng null thực tế là một con số, mà đúng hơn là null không phải là NaN. Điều này có lẽ là do cả hai được thể hiện khác nhau trong JS để chúng sẽ không chính xác như nhau, theo cùng một cách 9! == '9'.



0

Ghi chú:

"1" == 1 // true
"1" === 1 // false

Toán tử == thực hiện chuyển đổi loại, trong khi === thì không.

Trang web của Douglas Crockford , một Yahoo! Nhà truyền giáo JavaScript, là một nguồn tài nguyên tuyệt vời cho những thứ như thế này.

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.