The front reminds: the length is longer, the point likes or the collection, can be in the next reading convenient search

When it comes to js implicit conversion, many people’s first reaction is: pit.

Indeed, for unfamiliar people, js implicit conversion there are a lot of unpredictable places, I believe that many people are suffering from it, so, in the development process, we may use === to try to avoid implicit conversion. However, in order to understand javascript more deeply, in the spirit of knowledge desire, we will analyze JS implicit conversion through a large number of examples, familiar with the rules of JS implicit conversion, so that it becomes “explicit” in your eyes.

Start with an interview question

Let’s start with a classic interview question

Define a variable a such that the following expression results in true

  a == 1 && a == 2 && a == 3
Copy the code

And this operation? So let’s try it out. Define a = true?

  var a = true
  a == 1 && a == 2 && a == 3 // false
Copy the code

But did not reach the expected, as if touch knowledge blind area… That’s okay. Put it down. Let’s see some of the worse ones

[] = =! []// true[] = =0 // true
  
  [2] = =2 // true

  ['0'] = =false // true

  '0'= =false // true[] = =false // true

  [null] = =0 // true

  null= =0 // false

  [null] = =false // true

  null= =false // false

  [undefined] = =false // true

  undefined= =false // false
Copy the code

Confused? It doesn’t matter! Let’s take you through javascript implicit conversions.

Javascript implicit conversion rules

1. ToString, ToNumber, ToBoolean, ToPrimitive

We need to understand the basic rules for converting between JS data types, such as numbers, strings, Bools, arrays, and objects.

1.1 the ToString

ToString is not the ToString method of an object, but the operation that converts a value of another type to a string.

Here we discuss the rules for converting null, undefined, Booleans, numbers, arrays, and ordinary objects to strings.

  • Null: to"null"
  • Undefined: to"undefined"
  • Boolean type:trueandfalseBe converted to"true"and"false"
  • Number type: A string converted to a number, for example10to"10".1e21to"1e+21"
  • Array: Converting to a string concatenates all elements according to “,”, which is equivalent to calling an arrayArray.prototype.join()Methods, such as[1, 2, 3]to"1, 2, 3", an empty array[]To an empty string in an arraynullorundefinedIs treated as an empty string
  • Normal object: Converting to a string is equivalent to using it directlyObject.prototype.toString()To return to"[object Object]"
  String(null) // 'null'
  String(undefined) // 'undefined'
  String(true) // 'true'
  String(10) / / '10'
  String(1e21) // '1e+21'
  String([1.2.3]) / / '1, 2, 3'
  String([]) / /"
  String([null]) / /"
  String([1.undefined.3]) / / ', 1, 3 '
  String({}) // '[object Objecr]'
Copy the code

Object to the toString method, which satisfies the toString operation rules.

Note: The rules described above are by default, and changing the default toString() method will result in different results

1.2 ToNumber

ToNumber refers to operations that convert other types to numeric types.

  • Null: to0
  • Undefined: toNaN
  • String: If it is a pure number, it is converted to the corresponding number, and empty characters are converted to0Otherwise, the conversion will be processed as conversion failureNaN
  • Boolean:trueandfalseBe converted to1and0
  • Arrays: Arrays are first cast to their primitive type, i.eToPrimitive, and then according to the converted original type according to the above rules, aboutToPrimitive, will be covered below
  • Objects: Same as arrays
  Number(null) / / 0
  Number(undefined) // NaN
  Number('10') / / 10
  Number('10a') // NaN
  Number(' ') / / 0
  Number(true) / / 1
  Number(false) / / 0
  Number([]) / / 0
  Number(['1']) / / 1
  Number({}) // NaN
Copy the code

1.3 ToBoolean

ToBoolean refers to the operation that converts other types to Booleans.

The only false values in js are false, null, undefined, null, 0, and NaN. All other values are true when converted to Boolean.

  Boolean(null) // false
  Boolean(undefined) // false
  Boolean(' ') // flase
  Boolean(NaN) // flase
  Boolean(0) // flase
  Boolean([]) // true
  Boolean({}) // true
  Boolean(Infinity) // true
Copy the code

1.4 ToPrimitive

ToPrimitive Refers to the operation of converting an object type (such as an object or array) to a primitive type.

  • When an object type needs to be converted to a primitive type, it looks for the object firstvalueOfMethod, ifvalueOfMethod returns a value of the original type, thenToPrimitiveThe result of phi is this value
  • ifvalueOfDoes not exist orvalueOfMethod returns a value other than the original type and attempts to call the objecttoStringMethods, that is, will follow the objectToStringRule, then usetoStringReturn value asToPrimitiveResults.

Note: ToPrimitive has different rules for different types of objects, such as Date objects that call toString first. For details, see the ECMA standard

If neither valueOf nor toString returns a valueOf the original type, an exception is thrown.

  Number([]) / / 0
  Number(['10']) / / 10

  const obj1 = {
    valueOf () {
      return 100
    },
    toString () {
      return 101}}Number(obj1) / / 100

  const obj2 = {
    toString () {
      return 102}}Number(obj2) / / 102

  const obj3 = {
    toString () {
      return{}}}Number(obj3) // TypeError
Copy the code

As mentioned earlier, the object type in ToNumber is ToPrimitive first and then based on the converted original ToNumber

  • Number([])Empty arrays are called firstvalueOf, but returns the array itself, not the original type, so the call continuestoString,An empty string, which is equivalent toNumber(''), so the result after transformation is"0"
  • In the same way,Number(['10'])The equivalent ofNumber('10'), get the result10
  • obj1thevalueOfMethod returns the original type100, soToPrimitiveAs the result of the100
  • obj2There is novalueOf, but there aretoStringAnd return a primitive type, soNumber(obj2)The results for102
  • obj3thetoStringMethod does not return a primitive typeToPrimitive, so an error is thrown

Look at this and think you’ve got it all figured out? Don’t forget that the interview question and a bunch of confusing judgments are still unresolved, so in the spirit of thirst for knowledge, read on.

2. Implicit conversion rules for loose equality (==) comparisons

The difference between loose equality (==) and strict equality (===) is that loose equality is implicitly converted in comparison. Now let’s look at the conversion rules for different cases.

2.1 Equality comparison between Boolean types and other types

  • As long asBoolean typeParticipate in the comparison, theBoolean typeThe value of is first converted toNumeric types
  • According to theBoolean typetheToNumberThe rules,trueto1.falseto0
  false= =0 // true
  true= =1 // true
  true= =2 // false
Copy the code

If the number 2 is a true value, then true == 2 should be true. If the number 2 is a true value, then true == 2 should be true

We usually write this when we use if judgment

  const x = 10
  if (x) {
    console.log(x)
  }
Copy the code

The x of if(x) here will be converted to a Boolean type, so the code will execute. But if I write it like this:

  const x = 10
  if (x == true) {
    console.log(x)
  }
Copy the code

The code will not execute as expected because x == true is equivalent to 10 == 1

2.2 Equality comparison between numeric types and string types

  • whenNumeric typesandString typeWhen I do an equality comparison,String typeWill be converted toNumeric types
  • According to the stringToNumberRule, if the string is in pure numeric form, it is converted to the corresponding number, and empty characters are converted to0Otherwise, the conversion will be processed as conversion failureNaN
  0= =' ' // true
  1= ='1' // true
  1e21= ='1e21' // true
  Infinity= ='Infinity' // true
  true= ='1' // true
  false= ='0' // true
  false= =' ' // true
Copy the code

Are the results of the above comparison consistent with your expectations? By rule, strings are converted to numbers, and booleans are converted to numbers, so the result is obvious.

NaN is not discussed here, because NaN is not equal to any value, including itself.

2.3 Equality comparison between object types and primitive types

  • whenObject typeandThe original typeWhen I do an equality comparison,Object typeWill be in accordance with theToPrimitiveRule conversion toThe original type
  '[object Object]'= = {}// true
  '1, 2, 3'= = [1.2.3] // true
Copy the code

Take a look at the example given at the beginning of this article

  [2] = =2 // true
Copy the code

Array [2] is an object type, so the ToPrimitive operation is performed, that is, valueOf is called first and then toString is called. According to the toString operation rules, the result “2” is obtained, and the string “2” is converted to a number when compared with the number 2. So the final result is true.

  [null] = =0 // true
  [undefined] = =0 // true[] = =0 // true
Copy the code

According to the array ToString rule mentioned above, when an array element is null or undefined, the element is treated as an empty string, and the empty array [] is converted to an empty string

  ' '= =0 // true
  ' '= =0 // true
  ' '= =0 // true
Copy the code

The empty string is converted to the number 0, so the result is true.

Try the valueOf method

  const a = {
    valueOf () {
      return 10
    }
    toString () {
      return 20
    }
  }
  a == 10 // true
Copy the code

The ToPrimitive operation on the ToPrimitive object calls the valueOf method first, and the valueOf method of a returns a primitive value, so the result of the ToPrimitive operation is the valueOf return valueOf 10.

At this point, are you thinking of the original interview question? Object each time and primitive types do = = comparison, will conduct a ToPrimitive operation, that if we can define a contains the valueOf method of object, and then by a value of cumulative?

Give it a try

  const a = {
    // Define an attribute to do the accumulation
    i: 1,
    valueOf () {
      return this.i++
    }
  }
  a == 1 && a == 2 && a == 3 // true
Copy the code

The result, as you would expect, is correct. Of course, the toString method is fine when valueOf methods are not defined.

  const a = {
    // Define an attribute to do the accumulation
    i: 1,
    toString () {
      return this.i++
    }
  }
  a == 1 && a == 2 && a == 3 // true
Copy the code

2.4 Comparison of NULL, undefined, and other types

  • nullandundefinedWe all know that loose equality is true

Second, null and undefined are false values, so

  null= =false // false
  undefined= =false // false
Copy the code

It’s not what I thought it was? Why is that? First, false turns to zero, and then what? No, the ECMAScript specification states that null and undefined are loosely equal to each other (==) and to themselves, but not to all other values (==).

The last

Now looking back at the previous code makes a lot of sense

[] = =! []// true[] = =0 // true
  
  [2] = =2 // true

  ['0'] = =false // true

  '0'= =false // true[] = =false // true

  [null] = =0 // true

  null= =0 // false

  [null] = =false // true

  null= =false // false

  [undefined] = =false // true

  undefined= =false // false
Copy the code

Finally, I want to tell you that we should not blindly reject javascript implicit conversion, should learn how to use it, your code may exist a lot of implicit conversion, but you ignore it, to be aware of it, and know why, so as to help us understand javascript in depth.

(Read so long, hard, but I also wrote for a long time ah, click a like before leaving)