A question was raised in an article [[js makes people complain about these features]].

I thought the problem was easy at first. Think you just need to remember a few features. So directly use the exhaustive method to carry out the regular combination.

But when console.log(Number([])) is encountered, the result is 0, and console.log(Number([1, 2])) is NaN. It is not to understand, although can be strong back down, but as a pursuit of programmers or to figure out how it is the same thing.

console.log({} - {}) // NaN
console.log([] - []) / / 0
console.log([] - [1.2]) // NaN
console.log([] == ! [])console.log({} == {})
Copy the code

Number([]); Number([1, 2]); Number({}); So understanding the following can help explain the problem.

1. Packaging

Boolean()

Boolean has only two results,true and false.

  • BooleanThe type whose result is false is usually calledfalsey, Chinese name isVirtual value. These values are mentioned in [[[js makes people complain about these features]], i.e.,

0, null, undefined, false, ”, NaN

There are some articles that double minus 0 and plus 0

These are all original values to original values. Everything else is true

If the value is converted from a reference value to the original value, the value will be true.

Boolean(/d/)
Boolean(new Error())
console.log(Boolean(Symbol()))
Copy the code
extension

There is also a slightly confusing typeof return result in node:

console.log(typeof Date())
console.log(typeof new Date()) 
console.log(Date()) // Thu Jan 13 202L2 22:29:36 GMT+0800
console.log(new Date()) / / the T14:2022-01-13 each. 660 z
Copy the code

Number()

Reference type conversion Number

Error prone is found in Number(). In particular, reference types are converted to primitive types. With that in mind, the first example will make sense.

Only when we know the rule of Number(reference type) can we determine the result of converting a reference type to the original type. Otherwise, it is impossible to determine the result by guessing.

  1. Let’s say we have an object that looks like this
const obj = {
  toString() {
    return 2	
  },
  valueOf() {
    return 1	
  }
}
Copy the code
  1. weNumber()Package it
console.log(Number(obj))
Copy the code

The printed result is 1. Oh, here’s the fun.

consot obj = {
  toString() {
    return 2	
  },
  valueOf() {
    return{}}}console.log(Number(obj)) / / 2
Copy the code

Let’s make valueOf print out 2 if it returns an object, or print out the String raw value and convert it to number.

In general, valueof is just a representative value, it doesn’t make sense, it doesn’t have to be handled. For example, [1, 2, 3].valueof () prints as [1, 2, 3].

We can also use this method to solve the [[let a == 1&&a == 2&&a == 3]] problem.

So it’s easy to follow the rule that when valueOf returns a reference, we take the value returned by toString. In a nutshell:

  1. ifvalueOfReturns the original value after wrapping Number
  2. If valueOf returns an object, gotoString()Methods to find
  3. iftoString()Returns the original value after wrapping Number
  4. iftoString()The object is returned and is overwritten by itself. Then report an error
  5. If it is not congested, the obejct.prototye.tostring method is called

Obviously, [[prototype chain]] is also involved here, so implicit transformation is not as simple as imagined.

And the object that we’re creating basically doesn’t talk about creating these two methods. So it’s an obvious method that inherits from Object. That is to say, we are studying the problem is, is the research Object. The prototype. ToString. Call () returns the value of the.

console.log(Object.prototype.tostring.call('123'));

console.log(Object.prototype.toString.call(123));

console.log(object.prototype.tostring.call(true));

console.log(Object.prototype.tostring.call(undefined));

console.log(Object.prototype.tostring.call(null));

console.log(Object.prototype.tostring.call(function){}));

console.log(Object.prototype.toString.call([1.2.3]));

console.log(Object.prototype.tostring.call(ff));
Copy the code

The printed result is as follows:

[object string]
[object Number]
[object Boolean]
[object Undefined]
[object Null]
[object Functionl]
[object Arrayl]
[object objectl]
Copy the code
Original type to Number
console.log(Number(undefined)) // NaN
console.log(Number (null)) / / 0
console.log(Number(true)) / / 1
console.log(Number (false)) / / 0
console.log(Number(NaN)) // NaN
console.1og(Number (Infinity))// Infinity
console.log(Number(' ') / / 0
console.log(Number(' ') / / 0
console.log(Number('123')) / / 123
Copy the code

There’s nothing to say. Just memorize it. Note that the value of Number, in addition to the usual use of the Number meaning, NaN, Infinity.

There are also some confusion points to watch out for:
console.log((123).toString()) / / 123
console.log(undefined.toString()) / / an error
console.log(nul.toString()) / / an error
Copy the code

Undefined and null do not wrap classes and are themselves basic types, so there are no other methods for gargling. So an error is reported.

extension
The Argument and the document
console.log(Object.toString.call(argument)) // [object Argument]
console.log(Object.toString.call(document)) // [object HTMLDocument]
Copy the code

HTMLDocument is an object type provided by the browser.

This can also be learned that the Object. The prototype. ToString method used widely, identify types of typeof pallet return values is much more powerful. Of course, each has its own usage scenario.

Handwritten typeof

Typeof comes with JScore and is not syntactic sugar. I was stunned when I first saw the interview question. Should I write typeof engine code by hand? Typeof null is object from the first version of JS.

But there are companies that take this test, and it’s kind of smart, really smart. So I took a look at other people’s interpretations of this on the Internet… Is to use the Object. The prototype. ToString. The result of the call () returns, in the cutting of the string, then return to go behind the words.

Is this it? Drop your pants and fart.

Number converts to non-binary
Number(0xfff) / / 4095
Number(070) / / 56
Copy the code

Number can be converted to decimal directly.

ParseInt and Number
Number('123abc') // NaN
Number('ad123') // NaN
Number('123') / / 123
Copy the code

[[parseInt]] is a good complement to Number()

parseInt('123abc') / / 123
parseInt('123asd1') / / 123
parseInt('ad123') // NaN
parseInt('123') / / 123
Copy the code

String()

Object.prototype.toString

Use the same Number() example for String()

const obj = {
  toString() {
    return 2	
  },
  valueOf() {
    return 1}}Copy the code

When I trigger String(obj), it’s the exact opposite of Number().

console.log(String(obj)) / / 2
Copy the code

Directly accessed is the toString() method.

const obj = {
  toString() {
    return{}},valueOf() {
    return 1}}console.log(String(obj)) / / 1
Copy the code

But if toString() returns a reference type, look above the valueOf() method. This is the exact opposite of Number(), but it makes sense.

Overriding the toString() and valueOf() methods is a good way to get an idea of the internal running rules.

, if you don’t rewrite the Object. The prototype. ToString. Call (Object), the return value for the Number () part of the content.

console.log(String({})) // [object Object]
Copy the code

Array.prototype.toString

There is nothing to say about this memory, just remove the [] from the outside.

console.log(String([1])) / / '1'
console.log(String([1.2])) / / '1, 2'
console.log(Array.prototype.toString.call([1])) / / '1'
console.log(Array.prototype.toString.call([1.2])) / / '1, 2'
Copy the code

Implicit transformation trigger rules

I said the rule of display transformation. Here are the rules that can trigger the implicit transformation.

The and operator rules are and [[operator priority]].

Boolean implicit transformation

Implicit transformation occurs when judgments are made.

if.switch.while.for(; ;) , &&, | |,! ,!!!!! ,? : three yuanCopy the code

Implicit conversion of number

Operators are used to calculate between numbers, as anyone with elementary school knowledge knows. It’s basically the same thing in JavaScript.

+ – * % = = ~ ~ & | ~ ^ < < < < <, operators and arithmetic operators

Implicit transformation is the hardest case

= =! == >= <= < >

The following example, also regarded as a frequent interview topic, recite the rest, or to know it to get such a result of the method.

console.log([] == ! [])// true
Copy the code

Personally, this is the most complicated example of implicit transformation. No more complicated than adding priority. Going back to this example, it looks like we’re comparing two arrays, or two special objects. B: Not really. I should explain the problem like this:

  1. So if you look at the equal sign and you see the comparison operation you have to convert both sides of the equal sign to Number
  2. From left to right,Number([]).[]It is a reference type and cannot get the original value directly
  3. valueOfIf you don’t get what you want, goArray.prototype.toString.call([])As you can see from the above, it returns the removal of [], the string' '.
  4. The left hand side isNumber('')So the return on the left side is naturally0.

So this is 0 ==! []. Then the transformation on the right, that’s easy.

  1. inBoolean()In one section, you can see that in addition tofalseyExcept, all the others are ture. With the blessing of,[]Will be carried out inBoolean()
  2. The right hand side istrue. ! trueIt is false
  3. Number(false)Is 0

If 0 == 0, then true.

console.log({} == {}) // false
console.log({} ! = {})Copy the code

If explained in the same analytical way:

  1. On both sidesNumber()The parcel.
  2. toString()After all is[obejct Object]
  3. Number('[obejct Object]')NaN
  4. So it turns out to be zeroconsole.log(NaN == NaN)The comparison of

NaN doesn’t want to wait to compare to any value

The topic is not difficult, but the comprehensive thing is still a little. With these two problems solved, the implicit transformation problem is at an end

Special circumstances

The easiest thing to remember is the string operator.

console.log(1 + '2' + '2') / / '122'
console.log(1 + + '2' + '2') / / '32'
console.log('A' - 'B' + '2') // 'NaN2'
console.log('A' - 'B' + 2) // NaN
Copy the code

Do you want js strings and any data types to be converted to strings? So to speak, handling symbol type directly outside of the error.

console.log(typeof (+ '2')) // number
Copy the code

I am, therefore, undpay and ‘

console.log(undefined= =null) // true
console.log(NaN= =NaN) // fasle
Copy the code
  • NaNThe meaning isnot a numberObviously, it’s not a number
  • NaNintypeofIs in thenumberType, but it has nothing to do with any number.

Do not use it for work

In 2022, we just need to understand how == works. At this point in time, the question of whether to use == or === in restatement work is no longer necessary