Tại sao isNaN (loạt Điên) (chuỗi có dấu cách) bằng sai?


160

Trong JavaScript, tại sao isNaN(" ")đánh giá false, nhưng isNaN(" x")đánh giá true?

Tôi đang thực hiện hoạt động số trên trường nhập văn bản, và tôi đang kiểm tra nếu lĩnh vực này là null, ""hoặc NaN. Khi ai đó nhập một số khoảng trắng vào trường, xác thực của tôi không thành công trên cả ba và tôi bối rối không biết tại sao nó lại vượt qua isNaNkiểm tra.


1
Hừm ... không chắc là nửa kia của chủ đề đã đi đâu. Bạn nên đọc, "JavaScript: Tại sao isNaN (" ") đánh giá là sai?"
IVR Avenger

Jes, đó là hành vi (trống hoặc không gian trả về sai cho isNaN), nhưng tôi không tìm thấy thông số kỹ thuật chính xác của chức năng này.
Lucero

Đây là một câu hỏi trả lời câu hỏi này: http://stackoverflow.com/questions/115548/why-is-isnannull-false-in-js
Lucero

Javascript về những vấn đề này có vẻ như voodoo! Bạn không bao giờ biết và lời giải thích luôn luôn khá phức tạp. "" == false // trueisNaN(" ") // false
João Pimentel Ferreira

Câu trả lời:


155

JavaScript diễn giải một chuỗi rỗng là 0, sau đó không thực hiện kiểm tra isNAN. Trước tiên, bạn có thể sử dụng parseInt trên chuỗi mà sẽ không chuyển đổi chuỗi trống thành 0. Kết quả sẽ thất bại làNAN.


53
Nhưng parseInt ("123abcd") trả về 123, có nghĩa là isNaN (parseInt ("123abcd")) sẽ trả về false trong khi nó sẽ trả về true!
Pawan Nogariya

11
Vậy làm thế nào về (IsNaN (chuỗi) || isNaN (parseInt (chuỗi)))
matt

5
Có 2 bước trong việc diễn giải isNaN(arg). 1) Chuyển đổi arg thành số, 2) Kiểm tra xem số đó có phải là giá trị số không NaN. Điều đó giúp tôi hiểu nó hơn.
xdhmoore

3
@Antonio_Haley Đợi một chút, tôi không hiểu. Nếu "JavaScript diễn giải một chuỗi rỗng là 0", tại sao parseInt ("") trả về NaN?
Jean-François Beauchamp

1
@ Jean-François Bạn nói đúng, câu lệnh đúng hơn sẽ là "isNaN diễn giải một chuỗi rỗng là 0", chứ không phải JavaScript.
Antonio Haley

82

Bạn có thể thấy điều này đáng ngạc nhiên hoặc có thể không, nhưng đây là một số mã kiểm tra để cho bạn thấy sự lập dị của công cụ JavaScript.

document.write(isNaN("")) // false
document.write(isNaN(" "))  // false
document.write(isNaN(0))  // false
document.write(isNaN(null)) // false
document.write(isNaN(false))  // false
document.write("" == false)  // true
document.write("" == 0)  // true
document.write(" " == 0)  // true
document.write(" " == false)  // true
document.write(0 == false) // true
document.write(" " == "") // false

vì vậy điều này có nghĩa là

" " == 0 == false

"" == 0 == false

nhưng

"" != " "

Chúc vui vẻ :)


5
+1 Bài đăng tuyệt vời. Bạn có thể thêm cách toán tử ba bằng (=== và! ==) phù hợp ở đây không?
uốn cong

2
Bạn nên thử NaN === NaN hoặc NaN == NaN ;-) Tôi không biết liệu tất cả điều này có nghĩa là công cụ javascript bị lập dị hay mặc dù javascript có hại cho lập trình viên lập dị.
KooiInc

10
@Kooilnc thực tế là NaN! = NaN thực sự là một lựa chọn tốt cho một lần. Ý tưởng là NaN hầu như luôn là kết quả của một tính toán khác với cách lập trình viên dự định và giả sử rằng kết quả của hai phép tính "sai" là khá nguy hiểm, tôi nói.
skrebbel

2
@Kooilnc không lấy đi một chút từ sự lập dị của javascript, nhưng những NaN này chỉ tuân theo tiêu chuẩn điểm nổi IEEE 754. Bạn có thể đọc TẤT CẢ về nó như thường lệ trên W lớn: en.wikipedia.org/wiki/NaN
Spike0xff

@NickBerardi F'ing LOL! Tôi rất vui vì tôi đã thấy bài viết này. Đã giúp tôi tìm ra lý do tại sao hàm isNaN bị chậm như vậy. Tôi sẽ tước nó khỏi mã chưa được phát triển đầy đủ của tôi ngay bây giờ và có thể sẽ không bao giờ sử dụng nó nữa. Tôi sẽ xác nhận cho null, """ "bản thân mình. Cảm ơn!
VoidKing

16

Để hiểu rõ hơn, vui lòng mở Ecma-Script spec pdf trên trang 43 "ToNumber Áp dụng cho Loại chuỗi"

nếu một chuỗi có cú pháp số, có thể chứa bất kỳ số lượng ký tự khoảng trắng nào, thì chuỗi đó có thể được chuyển đổi thành loại Số. Chuỗi rỗng ước tính thành 0. Ngoài ra, chuỗi 'Infinity' sẽ cung cấp

isNaN('Infinity'); // false

13

Hãy thử sử dụng:

alert(isNaN(parseInt("   ")));

Hoặc là

alert(isNaN(parseFloat("    ")));

3
hi sir, isNaN (parseInt ( "123a")): sẽ trả lại 123 vì vậy giải pháp ur sẽ không làm việc, nếu chuỗi chứa aplha số
Sajjad Ali Khan

6

Từ MDNlý do cho vấn đề bạn đang phải đối mặt

Khi đối số cho hàm isNaN không có kiểu Số, giá trị đầu tiên được ép buộc thành Số. Giá trị kết quả sau đó được kiểm tra để xác định xem đó có phải là NaN hay không.

Bạn có thể muốn kiểm tra câu trả lời toàn diện sau đây bao gồm cả so sánh NaN về sự bình đẳng.

Cách kiểm tra nếu một biến JavaScript là NaN


5

Tôi nghĩ đó là do cách gõ của Javascript: ' 'được chuyển thành 0, trong khi đó 'x'không phải là:

alert(' ' * 1); // 0
alert('x' * 1); // NaN

4

Nếu bạn muốn triển khai một hàm isNumber chính xác, đây là một cách để thực hiện điều đó từ Javascript: The Good Parts của Douglas Crockford [trang 105]

var isNumber = function isNumber(value) {
   return typeof value === 'number' && 
   isFinite(value);
}

4
@Xyan trong trường hợp chức năng này không hữu ích để thực hiện nhiệm vụ mà OP yêu cầu thực hiện, đó là kiểm tra chuỗi đại diện của một số ...
ErikE

sử dụng toán tử bình đẳng nghiêm ngặt được gọi là bất kỳ giá trị đã cho nào đối với một chuỗi ký tự như "số" là ngu ngốc,
Bekim Bacaj

4

Câu trả lời không hoàn toàn chính xác

Câu trả lời được đánh giá cao và được chấp nhận của Antonio Haley ở đây đưa ra một giả định sai lầm rằng quy trình này đi qua parseIntchức năng của JavaScript :

Bạn có thể sử dụng parseInt trên chuỗi ... Kết quả sẽ thất bại làNAN.

Chúng ta có thể dễ dàng từ chối tuyên bố này với chuỗi "123abc":

parseInt("123abc")    // 123     (a number...
isNaN("123abc")       // true     ...which is not a number)

Với điều này, chúng ta có thể thấy rằng parseInthàm của JavaScript trả về "123abc"dưới dạng số 123, tuy nhiên isNaNhàm của nó cho chúng ta biết đó "123abc" không phải là số.

Câu trả lời đúng

ECMAScript-262 định nghĩa cách isNaNkiểm tra hoạt động trong phần 18.2.3 .

18.2.3 isNaN(Số)

Các isNaNchức năng là %isNaN%đối tượng nội tại. Khi isNaNhàm được gọi với một số đối số, các bước sau được thực hiện:

  1. Để numđược? ToNumber(number).
  2. Nếu numNaN, trở về true.
  3. Nếu không, trở lại false.

Các ToNumberchức năng đó tài liệu tham khảo cũng được định nghĩa trong ECMAScript-262 của phần 7.1.3 . Ở đây, chúng ta được cho biết cách JavaScript xử lý các chuỗi được truyền vào hàm này.

Ví dụ đầu tiên được đưa ra trong câu hỏi là một chuỗi không chứa gì ngoài các ký tự khoảng trắng. Phần này nói rằng:

A StringNumericLiteraltrống hoặc chỉ chứa khoảng trắng được chuyển đổi thành +0.

Các " "vì thế chuỗi ví dụ được chuyển thành +0, đó là một con số.

Phần tương tự cũng nêu:

Nếu ngữ pháp không thể hiểu Stringlà sự mở rộng của StringNumericLiteral, thì kết quả ToNumberNaN.

Không trích dẫn tất cả các kiểm tra có trong phần đó, " x"ví dụ đưa ra trong câu hỏi rơi vào điều kiện trên vì nó không thể được hiểu là a StringNumericLiteral. " x"do đó được chuyển đổi thành NaN.


2

Tôi không chắc tại sao , nhưng để giải quyết vấn đề, bạn luôn có thể cắt bớt khoảng trắng trước khi kiểm tra. Bạn có thể muốn làm điều đó anyway.


4
một chuỗi rỗng được cắt xén cũng thất bại trong bài kiểm tra isNaN.
Egemenk

2

Hàm isNaN("")thực hiện cưỡng chế kiểu String to Number

ECMAScript 3-5 định nghĩa các giá trị trả về sau cho toán tử typeof:

  • chưa xác định
  • đối tượng (null, đối tượng, mảng)
  • boolean
  • con số
  • chuỗi
  • chức năng

Tốt hơn để bọc thử nghiệm của chúng tôi trong một cơ thể chức năng:

function isNumber (s) {
    return typeof s == 'number'? true
           : typeof s == 'string'? (s.trim() === ''? false : !isNaN(s))
           : (typeof s).match(/object|function/)? false
           : !isNaN(s)
}

Hàm này không có ý định kiểm tra loại biến , thay vào đó, nó kiểm tra giá trị cưỡng chế . Chẳng hạn, booleans và chuỗi bị ép buộc thành số, vì vậy có lẽ bạn có thể muốn gọi hàm này làisNumberCoerced()

nếu không cần kiểm tra các loại khác ngoài chuỗisố , thì đoạn mã sau có thể được sử dụng như một phần của một số điều kiện:

if (!isNaN(s) && s.toString().trim()!='') // 's' can be boolean, number or string
    alert("s is a number")

1

Tôi khuyên bạn nên sử dụng hàm sau nếu bạn thực sự muốn kiểm tra đúng nếu đó là số nguyên:

function isInteger(s)
{
   return Math.ceil(s) == Math.floor(s);
}

1

Đó isNaN(" ")là sai là một phần của hành vi khó hiểu của isNaNhàm toàn cục do sự ép buộc của nó không phải là số thành một kiểu số.

Từ MDN :

Kể từ các phiên bản đầu tiên của isNaNđặc tả chức năng, hành vi của nó đối với các đối số không phải là số đã gây nhầm lẫn. Khi đối số cho isNaNhàm không có kiểu Số, giá trị đầu tiên được ép buộc thành Số. Giá trị kết quả sau đó được kiểm tra để xác định xem nó có NaN. Do đó, đối với các số không bị ép buộc thành kiểu số dẫn đến giá trị số không phải là NaN hợp lệ (đáng chú ý là các chuỗi nguyên gốc và chuỗi boolean trống, khi được ép buộc sẽ đưa ra các giá trị số bằng 0 hoặc một), giá trị trả về "false" có thể là bất ngờ; chuỗi rỗng, ví dụ, chắc chắn là "không phải là một số."

Cũng lưu ý rằng với ECMAScript 6, giờ đây cũng có Number.isNaNphương thức, theo MDN:

So với isNaN()hàm toàn cục , Number.isNaN()không gặp phải vấn đề chuyển đổi mạnh mẽ tham số thành số. Điều này có nghĩa là giờ đây an toàn để chuyển các giá trị thường chuyển đổi sang NaN, nhưng thực tế không phải là giá trị tương tự NaN. Điều này cũng có nghĩa là chỉ các giá trị của số loại, đó cũng là NaNtrả về true.

Thật không may :

Ngay cả Number.isNaNphương pháp ECMAScript 6 cũng có các vấn đề riêng, như được nêu trong bài đăng trên blog - Khắc phục sự cố xấu về JavaScript và ES6 NaN .


1

Các isNaNchức năng hy vọng một số như là đối số của nó, vì vậy đối số của bất kỳ loại khác (trong trường hợp của bạn một string) sẽ được chuyển đổi sang số trước logic chức năng thực tế được thực hiện. (Xin lưu ý rằng đó NaNcũng là một giá trị của loại Số!)

Btw. điều này là phổ biến cho tất cả các hàm dựng sẵn - nếu họ mong đợi một đối số của một loại nhất định, đối số thực tế sẽ được chuyển đổi bằng cách sử dụng các hàm chuyển đổi tiêu chuẩn. Có các chuyển đổi tiêu chuẩn giữa tất cả các loại cơ bản (bool, chuỗi, số, đối tượng, ngày, null, không xác định.)

Việc chuyển đổi tiêu chuẩn cho Stringđến Numbercó thể được gọi rõ ràng với Number(). Vì vậy, chúng ta có thể thấy rằng:

  • Number(" ") đánh giá 0
  • Number(" x") đánh giá NaN

Với điều này, kết quả của isNaNchức năng là hoàn toàn hợp lý!

Câu hỏi thực sự là tại sao chuyển đổi String-to-Number tiêu chuẩn hoạt động giống như vậy. Chuyển đổi chuỗi thành số thực sự nhằm chuyển đổi các chuỗi số như "123" hoặc "17.5e4" thành các số tương đương. Đầu tiên chuyển đổi bỏ qua khoảng trắng ban đầu (vì vậy "123" là hợp lệ) và sau đó cố gắng phân tích phần còn lại dưới dạng số. Nếu nó không được phân tích cú pháp dưới dạng số ("x" không) thì kết quả là NaN. Nhưng có một quy tắc đặc biệt rõ ràng rằng một chuỗi trống hoặc chỉ khoảng trắng được chuyển đổi thành 0. Vì vậy, điều này giải thích việc chuyển đổi.

Tham khảo: http : //www.ecma-i Intl.org/ecma-262/5.1/#sec-9.3.1


1

Tôi đã viết chức năng nhỏ nhanh chóng này để giúp giải quyết vấn đề này.

function isNumber(val) {
     return (val != undefined && val != null && val.toString().length > 0 && val.toString().match(/[^0-9\.\-]/g) == null);
};

Nó chỉ đơn giản kiểm tra bất kỳ ký tự nào không phải là số (0-9), không phải là '-' hoặc '.' Và không xác định, không hoặc trống và trả về giá trị đúng nếu không có kết quả khớp. :)


Một lời cảm ơn muộn màng cho điều này; Điều này giải quyết vấn đề của tôi rất độc đáo.
Henry

1

Như đã giải thích khác, isNaNhàm sẽ ép chuỗi rỗng thành một số trước khi xác thực nó, do đó thay đổi một chuỗi rỗng thành 0 (là số hợp lệ). Tuy nhiên, tôi thấy rằng parseInthàm sẽ trở lại NaNkhi cố phân tích một chuỗi rỗng hoặc một chuỗi chỉ có khoảng trắng. Vì vậy, sự kết hợp sau đây dường như đang hoạt động tốt:

if ( isNaN(string) || isNaN(parseInt(string)) ) console.log('Not a number!');

Kiểm tra này sẽ hoạt động đối với các số dương, số âm và số có dấu thập phân, vì vậy tôi tin rằng nó bao gồm tất cả các trường hợp số phổ biến.


1

NaN ! == "không phải là số"

NaN là một giá trị của Loại số

đây là định nghĩa của isNaN () trong ECMAScript

1. Let num be ToNumber(number).
2. ReturnIfAbrupt(num).
3. If num is NaN, return true.
4. Otherwise, return false.

Cố gắng chuyển đổi bất kỳ giá trị thành Số.

Number(" ") // 0
Number("x") // NaN
Number(null) // 0

Nếu bạn muốn xác định xem giá trị là gì NaN, trước tiên bạn nên thử chuyển đổi nó thành giá trị Số.


0

Chức năng này dường như hoạt động trong các thử nghiệm của tôi

function isNumber(s) {
    if (s === "" || s === null) {
        return false;
    } else {
        var number = parseInt(s);
        if (number == 'NaN') {
            return false;
        } else {
            return true;
        }
    }
}

2
Toàn bộ chức năng của bạn có thể được viết:return !(s === "" || s === null || parseInt(s) == 'NaN');
ErikE

0

Thế còn

function isNumberRegex(value) {        
    var pattern = /^[-+]?\d*\.?\d*$/i;
    var match = value.match(pattern);
    return value.length > 0 && match != null;
}

0

Hàm isNaN tích hợp sẵn của JavaScript , theo mặc định - như được mong đợi - một "Toán tử kiểu động". Do đó, tất cả các giá trị (trong quá trình DTC) có thể mang lại một giá trị đúng đơn giản | sai như , không thể là NaN."", " ", " 000"

Có nghĩa là đối số được cung cấp trước tiên sẽ trải qua chuyển đổi như trong:

function isNaNDemo(arg){
   var x = new Number(arg).valueOf();
   return x != x;
}

Giải trình:

Trong dòng trên cùng của thân hàm, chúng tôi (đầu tiên) đang cố gắng chuyển đổi thành công đối số thành một đối tượng số. Và (thứ hai), sử dụng dot điều hành chúng tôi - để thuận tiện của chúng ta - ngay lập tức tước, các nguyên giá trị của đối tượng được tạo ra.

Trong dòng thứ hai, chúng ta đang lấy giá trị thu được ở bước trước và lợi thế của thực tế là NaN không bằng bất cứ thứ gì trong vũ trụ, thậm chí không phải là chính nó, ví dụ: NaN == NaN >> falseđể cuối cùng so sánh nó (về sự bất bình đẳng) với chính nó .

Theo cách này, hàm trả về sẽ chỉ mang lại đúng khi và chỉ khi, trả về đối số được cung cấp, là một nỗ lực chuyển đổi không thành đối tượng số, tức là số không phải là số; ví dụ: NaN.


isNaNstatic ()

Tuy nhiên, đối với Toán tử loại tĩnh - nếu cần và khi cần - chúng ta có thể viết một hàm đơn giản hơn nhiều như:

function isNaNstatic(x){   
   return x != x;
}

Và tránh DTC hoàn toàn để nếu đối số không rõ ràng là số NaN, nó sẽ trả về sai. Vì vậy, thử nghiệm đối với những điều sau đây:

isNaNStatic(" x"); // will return false bởi vì nó vẫn là một chuỗi

Tuy nhiên: isNaNStatic(1/"x"); // will of course return true.như sẽ chẳng hạn isNaNStatic(NaN); >> true.

Nhưng ngược lại isNaN, isNaNStatic("NaN"); >> falsebởi vì nó (đối số) là một chuỗi bình thường.

ps: Phiên bản tĩnh của isNaN có thể rất hữu ích trong các kịch bản mã hóa hiện đại. Và nó rất có thể là một trong những lý do chính khiến tôi mất thời gian để đăng bài này.

Trân trọng.


0

isNAN(<argument>)là một hàm để cho biết liệu đối số đã cho có phải là số bất hợp pháp hay không. isNaNđánh máy các đối số thành loại Số. Nếu bạn muốn kiểm tra xem đối số có phải là Số hay không? Vui lòng sử dụng $.isNumeric()chức năng trong jQuery.

Nghĩa là, isNaN (foo) tương đương với isNaN (Số (foo)) Nó chấp nhận bất kỳ chuỗi nào có tất cả các số là số vì lý do rõ ràng. Dành cho người cũ

isNaN(123) //false
isNaN(-1.23) //false
isNaN(5-2) //false
isNaN(0) //false
isNaN('123') //false
isNaN('Hello') //true
isNaN('2005/12/12') //true
isNaN('') //false
isNaN(true) //false
isNaN(undefined) //true
isNaN('NaN') //true
isNaN(NaN) //true
isNaN(0 / 0) //true

0

Tôi dùng cái này

    function isNotANumeric(val) {
    	if(val.trim && val.trim() == "") {
         return true;
      } else {
      	 return isNaN(parseFloat(val * 1));
      }
    }
    
    alert(isNotANumeric("100"));  // false
    alert(isNotANumeric("1a"));   // true
    alert(isNotANumeric(""));     // true
    alert(isNotANumeric("   "));  // true


0

Khi kiểm tra nếu giá trị chuỗi nhất định với khoảng trắng hoặc " "isNaNcó thể cố gắng để thực hiện xác nhận chuỗi, ví dụ:

// value = "123 " if (value.match(/\s/) || isNaN(value)) { // do something }

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.