This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

NaN and Number. NaN

NaN is A not-a-number, Not A Number. In JavaScript, both integers and floating point numbers are collectively called Number types.

Feature 1 Typeof is a number

Typeof (” number “, “number”); After ES6, Number also has a static NaN attribute

typeof NaN // number
typeof Number.NaN // number
Copy the code

Trait 2 I am not equal to myself

I deny myself, and that’s it. And, of course, there’s a plus 0 and a minus 0

NaN= =NaN  // false
Number.NaN == NaN // false
NaN= = =NaN // false
Number.NaN === NaN  // false

+0= = -0 // true
Object.is(+0, -0) // fasle
Copy the code

Description of NaN

It is a value that, in the new ES standard, is not configurable or enumerable. Delete cannot be deleted, cannot be overwritten, and cannot be overwritten.

delete NaN // false
NaN = 1 / / 1
NaN= =1 // false

delete Number.NaN // false
Number.NaN = 1 / / 1
Number.NaN == 1 // false
Copy the code

We tried rewriting: use reflect.defineProperty instead of Object.defineProperty, because the former will tell you exactly if you succeeded, while the latter returns the defined Object.

const success =Reflect.getOwnPropertyDescriptor(window.'NaN'), {
    writable: true.configurable: true,})console.log(success) // false
Reflect.getOwnPropertyDescriptor(window.'NaN')
// {value: NaN, writable: false, enumerable: false, configurable: false}
Copy the code

It turns out it can’t be rewritten, so don’t beat him up.

Common Scenarios

Computation, casting is a typical scenario

let print = console.log;
// parseInt 
print(isNaN(parseInt("zz123"))) // true

// parseFloat 
print(isNaN(parseFloat("zz123"))) // true

// Initialize Number directly
print(isNaN(Number("zz123"))) // true

// Number manipulation
print(isNaN(0 / 0 ))  // true
print(isNaN( 1 * "zz123" )) // true
print(Math.sqrt(-1)) // true

Copy the code

isNaN

IsNaN () is a global method. The essence of this is to check the value returned by toNumber, true if it is NaN and false if it is not.

Can be simplified to semantics:

Number.isNaN =  function (val){
   return Object.is(Number(val), NaN); 
}
Copy the code

ToNumber method, the general logic is as follows:

le 15: ToNumber Conversions

Argument Type Result
Undefined Return NaN.
Null Return + 0 𝔽.
Boolean If argumentIs true, return 1𝔽argumentIs false, return + 0 𝔽.
Number Return argument (no conversion).
String Return ! StringToNumber(argument).
Symbol Throw a TypeError exception.
BigInt Throw a TypeError exception.

1. Let primValue be? ToPrimitive(argument, number). 2. Return ? ToNumber(primValue).

The simple translation is to get the value of the original type and convert it to Number.

Taking the original value, different methods are executed depending on the condition.

  1. Top priority callSymbol.toPrimitive, if there is
  2. Whether to call valueOf or toString first depends on the condition

Object is a bit more interesting. In the following example, the return from valueOf can directly affect the valueOf isNaN.

let print = console.log;
var person = {
    age: 10.name: "tom".valueOf(){
        return this.name 
    }
}
print(isNaN(person))  // true


let print = console.log;
var person = {
    age: 10.name: "tom".valueOf(){
        return this.age 
    }
}
print(isNaN(person))  // false
Copy the code

General examples:

let print = console.log;
print(isNaN("123")) //false
print(isNaN('zz123')) //true
print(isNaN(NaN)) //true
Copy the code

IsNaN can be deleted, but cannot be enumerated:

delete isNaN // true
typeof // undefined

isNaN = 1  / / 1
isNaN= =1  //true
Copy the code

Attribute Description:

Number.isNaN

Determines whether a value is a number and is equal to NaN.

Description of ES standard:

  1. If Type(number) is not Number, return false.
  2. If number is NaN, return true.
  3. Otherwise, return false.

All can be semantically translated as:

Number.isNaN = function(val){
   if(typeofval ! = ="number") {return false
   }
   return Object.is(val, NaN);
}

Copy the code

demo:

let print = console.log;

print(Number.isNaN(NaN))  // false
print(Number.isNaN("123")) //true
Copy the code

IsNaN and number. isNaN

Number. IsNaN is a strict judgment and must be strictly equal to NaN. Is the value NaN

IsNaN is determined by internal toNumber transformation results. The return value of the Number conversion is NaN

Number. IsNaN is an ES6 syntax with some compatibility issues.

Object.is

ES6 standard added a method to determine whether two values belong to the same value, which can accurately determine NaN.

let print = console.log;

print(Object.is(NaN.NaN)); // true
print(Object.is("123".NaN)) // false
Copy the code

Strictly judge NaN summaries

Four, two ES6s, two ES5s.

Number.isNaN (ES6)

Number.isNaN(NaN) // true
Number.isNaN(1) // false
Copy the code

Object.is (ES6)

function isNaNVal(val){
    return Object.is(val, NaN);
}
isNaNVal(NaN) // true
isNaNVal(1) // false
Copy the code

Self comparison (ES5)

The simplest way to do it.

function isNaNVal(val){
    returnval ! == val; } isNaNVal(NaN) // true
isNaNVal(1) // false
Copy the code

typeof + NaN (ES5)

This is the MDN recommended gasket, some compatible with lower versions of the library is implemented in this way, is an accurate expression of the ES standard

function isNaNVal(val){
    return typeof val === 'number' && isNaN(val)
}
Copy the code

Integrated gasket

if(! ("isNaN" in Number)) {
    Number.isNaN = function (val) {
      return typeof val === 'number' && isNaN(val)
    }
}
Copy the code

Dig into the array indexOf and includes

NaN can be identified in this section.

var arr=[NaN];
arr.indexOf(NaN) // -1
arr.includes(NaN) // true
Copy the code

includes

Let’s take a closer look at the specification:

The ES standard array.prototype. includes method calls the internal SameValueZero (x, y) method, which checks if the first value is a number. Call Number::sameValueZero(x, y)

2. If x is +0𝔽 and y is-0 𝔽, return true. 3. If x is-0 𝔽 and y is +0𝔽, return true. 4. If x is the same Number value as y, return true. 5. Return false.

It compares nans first, so it can check nans. Here’s an additional piece of information: +0 and -0 are equal when comparing, and you have to use object.is to distinguish +0 from -0

indexOf

IndexOf (searchElement, elementK); Number::equal(x, y);

Its comparative logic

1. If x is NaN, return false. 2. If y is NaN, return false. 3. If x is the same Number value as y, If x is +0𝔽 and y is-0 𝔽, return true. 5. If x is-0 𝔽 and y is +0𝔽, return true. 6.

As you can see, if any NaN is returned, false will not be strictly checked for NaN.

Number::sameValueZero 和 Number::sameValue

The difference between

Array.prototype.includes Number::sameValueZero.

SameValue = sameValue = sameValue = sameValue = sameValue = sameValue

It can be seen thatNumber::sameValueZeroDoes not distinguish between+0 -0.Number::sameValueThe distinction.

Object.is(+0, -0) // false to distinguish +0 from -0
[-0].includes(+0) // true, regardless of +0,-0

Copy the code

BigInt: : sameValue and BigInt: samgeValueZero

In addition to Number, BigInt has similar comparisons.

The main application scenarios of these two methods are Object.is and array.prototype. includes.

And guess the following:

Object.is(BigInt(+0),BigInt(-0))
Object.is(-0n.0n)
Object.is(-0.0)
[BigInt(+0)].includes(BigInt(-0))
Copy the code

3 2 1 Result, not as you expected:

Object.is(BigInt(+0),BigInt(-0))   // true
Object.is(-0n.0n) // true
Object.is(-0.0) // false
[BigInt(+0)].includes(BigInt(-0))  // false
Copy the code

BigInt::equal (x, y) :

Call BigInt::sameValue (x, y) to equal (x, y)

BigInt::equal (x, y) 1. If ℝ(x) = ℝ(y), return true; otherwise return false.

And R of x is something

The conversion from Number or BigInt x to a mathematical value is represented as “the mathematical value of x” or R(x). The mathematical value of + 0F and -0f is 0

Simple conclusion:

  1. Number区分+0,- 0
  2. BitInt does not distinguish between

What is the difference between BigInt::sameValue and BigInt:samgeValueZero? Here’s a picture to illustrate:

No difference, what’s the more reasonable explanation? Perhaps inheriting from the same parent class??

summary

IndexOf is a product of ES5 and even earlier, includes is a product of ES6. Advanced products toward a more reasonable direction of development, reasonable.

As for why not upgrade indexOf, the historical baggage, the old code can’t make it unexpected.

Write in the last

Please go to the technical exchange groupCome here,. Or add my wechat Dirge-Cloud and take me to learn together.

reference

IsNaN isNaN “ten thousand word summary” stay up late to summarize 50 JS advanced knowledge points, all will you are god!!