A == ‘juejin’ && a == 666 && A == 888 is true. Javascript is sometimes so magic, the above expression is implemented through the JS implicit conversion part of the knowledge, that let us first understand the implicit conversion, and then try to implement the above expression.

What is an implicit conversion

In javascript, when an operator is operating, if the data types on both sides of the operator are not consistent, the CPU cannot perform the operation. In this case, javascript will automatically convert the data on both sides of the operator to the same data type for calculation. This method of automatic conversion by the compiler without manual conversion by the programmer is called implicit conversion.

When an operation is performed on the reference type and the underlying type, the reference type is converted to the underlying type. In javascript, each reference type has its own built-in methods, of which there are two built-in methods valueOf() and toString():

  • ToString (): Returns a string representation of an object.
  • ValueOf (): Returns the string, numeric, or Boolean representation of an object. Usually the same as the return value of toString().

They can implicitly convert Object types to base types for operations and comparisons.

Different type conversion rules

Knowing that implicit conversions require converting different types to the same type, we need to look at the rules for converting different types.

First, JS currently has basic types: number, String, Boolean, undefined, NULL, and symbol. The reference type is Object.

Js specifies that undefined == null, and other types cannot be converted to undefined and NULL. Most of the other types are interchangeable.

Other types -> number types

string -> number

  • If the content of the string is purely numeric, the result is converted to a number
  • If the contents of the string are not pure numbers, the result is converted to NaN
Number('1272421')  / / 1272421
Number('ok111')    // NaN
Copy the code

boolean -> number

  • true -> 1
  • false -> 0
Number(true)   / / 1
Number(false)  / / 0
Copy the code

undefined -> number

  • undefined -> NaN
Number(undefined)   // NaN
Copy the code

null -> number

  • null -> 0
Number(null)   / / 0
Copy the code

Object -> number

  • Call the valueOf() method first to see if you can get a base type, and if so, convert it using Number()
  • If valueOf() does not get an underlying type, call toString() to see if it can get one. If so, convert the underlying type using Number(). If not, report an error
// Objects that do not implement custom valueOf() and toString()
const a = { value: 1 }
Number(a)  // NaN
// Custom valueOf() returns the base type
const b = {
    valueOf() {
        return 6}}Number(b)  / / 6
// Custom toString() returns the base type
const c = {
    toString() {
        return 7}}Number(c)  / / 7
// Both valueOf() and toString() are customized not to return base types
const d = {
    valueOf() {
        return{}},toString() {
        return{}}}Number(d)  // Uncaught TypeError: Cannot convert object to primitive value
Copy the code

Other types -> String

Base type -> String

  • The base type is converted to string, which is equivalent to being directly outside""To string content
String(Awesome!)   / / "666"
String(true)  // "true"
String(undefined)  // "undefined"
String(null) // "null"
Copy the code

Object -> string

  • Call toString() first to see if you can get a base type, and if so, use String() to convert the base type
  • If toString() does not get an underlying type, call valueOf() to see if it can get one. If so, use String() to convert the underlying type. If not, report an error
// Objects that do not implement custom valueOf() and toString()
const a = { value: 1 }
Number(a)  // "[object Object]"
// Custom toString() returns the base type
const b = {
    valueOf() {
        return "ok"}}String(b)  // "ok"
// Custom valueOf() returns the base type
const c = {
    toString() {
        return "hello"}}String(c)  // "hello"
// Both valueOf() and toString() are customized not to return base types
const d = {
    valueOf() {
        return{}},toString() {
        return{}}}String(d)  // Uncaught TypeError: Cannot convert object to primitive value
Copy the code

Other types -> Boolean

  • Undefined null 0 -0 +0 NaN ” converts to false
  • All other types and values are converted to true
Boolean(undefined) // false
Boolean({}) // true
Copy the code

== Compare rules

Base type comparison

  • Undefined is equal to null
  • When string is compared with number, string is converted to number
  • When number and Boolean are compared, Boolean is changed to number
  • When string and Boolean are compared, they are converted to number
undefined= =null;    //true
'0'= =0;//true, string to number
0= =false;           //true, Boolean to number
'0'= =false;//true
Copy the code

A reference type is compared to an underlying type

The reference type is compared to the base type. As mentioned above, the valueOf() and toString() methods convert the reference type to the base type and then compare. The conversion rules mentioned above give priority to valueOf() when converting a reference to number and toString() when converting a reference toString.

But there is a difference when using == for comparison:

  • Compared to Boolean types, both are converted to true
  • ValueOf () is used to see if it can be converted to the base type. If it can be converted to the corresponding number or string, valueOf() is used to compare the base type. If not, use toString() for conversion

Implement a == ‘juejin’ &&a == 666&&a == 888

Now that we understand the implicit conversion rules above, we can think about how to implement them.

We can customize valueOf() to return ‘juejin’ on the first comparison, 666 on the second, and 888 after that:

const a = {
 count: 0.// Record the current number of comparisons
 valueOf() {
   this.count++;
   if(this.count === 1) {
     return 'juejin'
   } else if(this.count === 2) {
     return Awesome!
   } else {
     return 888}}}console.log(a == 'juejin' && a == Awesome! && a == 888)  // true
Copy the code

This implements true as an expression in the title.