Implicit conversion comparison is an inescapable obstacle in JS, and even engineers with a few years of experience are likely not familiar with this knowledge. Even if you know how to use the === comparison to avoid the pit, the rest of the team may not be aware of the pit, and people with experience with back-end languages often fall into the trap of thinking, “JS is a simple language, just look at the syntax and find a few examples to manipulate the DOM and write special effects.” As react, VUE, HTML5 and other technologies are widely used in projects, more and more projects use JS, and even the whole project is written in JS (such as SPA management background based on WebAPI, wechat mini program, wechat H5 application, Hybrid App). If you do not learn JS in depth, Without changing your mindset, your application is likely to have bugs in these areas, hidden bugs that are very difficult to find if you are not familiar with JS. Now to begin today’s discussion, please write your answers on a piece of paper first.

console.log(newString('abc') = =true)
console.log({}==true) console.log([]==! [])Copy the code

If you answered: true, true, false, congratulations, you got everything wrong, your thinking might be as follows:

{} is a literal object, which is converted to a Boolean value of true,true==true, and the result is true 3. Right there! Operator, highest priority, first to the right. An array is an object that converts to a Boolean value to true! The result of [] is false, the expression to compare becomes []=false, and the array is converted to true,true==false, and the result is false

Why didn’t you get any of the questions right? If you are most likely not familiar with the concept of objects in JS, the special rules for NULL, and the conversion rules for the == operator, here are a few things to consider.

Variable literal form, wrapper mode, new mode difference

var a='xxx'Var a= string ();'abc'Var a=new String(); var a=new String();'abc'// An object type is created when the new method is usedCopy the code

Verify the above conclusion using Typeof

var a='abc'
console.log(typeof a) //string
console.log(typeof String('abc')) //string
console.log(typeof(new String('abc'))) //object
Copy the code

Which types are object types? In addition to the literal object ({}) arrays, dates, regular expressions, Math, function expressions, and function declarations, all of which are of type Object. Var a=function(){} var a=function(){} var a=function(){} var a=function(){} var a=function(){} Call new Function(‘ parameter 1′,’ parameter 2′,’ Function body ‘); typeof returns Function(Function); This is an issue left over from history.

JavaScript data types

The rules for basic types and object types are different when using the equal character, so it’s worth reviewing the data types in JS again. JavaScript has six basic data types: String, Boolean, number, NULL, undefined, symbol (newly added in ES6), and one more complex data type: Object. Data types can be divided into value types and reference types depending on how the data is stored in memory. Value type data is stored in the stack, whereas reference type data has a pointer in the stack, object name, function name, etc., that points to the data in the heap. The basic data types are all value types. The object type is a reference type. The following is a storage diagram.

All types are implicitly converted to the Boolean type comparison table

Why do you want to list this suddenly? Because it is used frequently, related questions often come up in the interview, so you need to keep in mind. For example, if we have a variable a, we need to execute the code if the variable a is not undefined, and if you don’t know the implicit conversion, you’ll probably write if(a===undefined), which is fine, but it’s hard to type, and it’s a few extra bytes. Here I directly copied the JS elevation design on the table.

Four,! Conversion rules of

When you use this symbol, you first cast the data after the operator to a Boolean type and then invert it, nothing special. A classic use of this operator enforces a variable to be true or false

Var a; var b=!! a;Copy the code

The role of this code is the value of variable b is true or false, only when a is undefined, the value of b is false, otherwise it is true, of course, also can use var b = a | | false to achieve the same effect, personally, I prefer the latter. The principle behind this is # 3 above, so it is important to have a firm understanding of implicit conversions

V. Conversion rules of ==

The comparison operator converts two operands of different types and then performs a strict comparison. When two operands are both objects, JavaScript compares their internal references to be equal if and only if their references refer to the same object (region) in memory; that is, they refer to the same address in stack memory. In case I’m misled by some of the summaries I’ve seen on blogs, I specifically looked up the description of the type conversion rule on MDN:

  1. When comparing numbers and strings, strings are converted to numeric values. JavaScript attempts to convert numeric literals to numeric values.
  2. If one of the operands is Boolean, the Boolean type is first converted to numeric.
  3. If an object is compared to a number or string, JavaScript tries to return the object’s default value. The operator attempts to convert an object to its original value (a string or numeric value) through the methods valueOf and toString. If the conversion attempt fails, a runtime error is generated.
  4. Note: Objects are converted to the original value if and only if compared to the original value. When both operands are objects, they are compared as objects and return true only if they reference the same object.

The official document is always difficult to read, translated into plain English plus JS elevation design book said special circumstances, summed up the following points:

1. If both sides of the conversion are reference types, compare the address directly in memory (i.e. the address to which the pointer points).

 console.log([]==[]) //false, Pointers to different addressesCopy the code

ValueOf () is called first. If valueOf() can be converted to a number, then toString() can be converted to a string.

 var a='123'
  console.log(a==false) / /false.'123'123==0 console.log(a==123) //true, the right side is the number, directly convert left and right can beCopy the code

Object type comparison

 var a=new String(123)
 console.log(a==123) //true,a. valueof () the result is the number 123, and the final comparison is 123==123Copy the code

Let’s do another example

Var a={} console.log(a==1) // A ==1 is executed in the js interpretation engine as follows: // a.valueof () is not a basic type'[object Object]'
'[object Object]'= = 1; // The left side is a number NaN==1; //falseNaN is equal to any typefalse
Copy the code

3. When comparing null, NaN, and undefined with string, number, Boolean, and object, implicit conversion is not performed. The comparison result is directly false. But there are a few rules to be aware of:

   console.log(NaN==NaN) //false
   console.log(undefined==null) //true
   console.log(null==null) //true
   console.log(null==undefined) //true
Copy the code

Figure out the above rules, the beginning of the several questions are particularly simple, and the million changes from its ancestor. Let’s go through it step by step.

  console.log(new String('abc') = =true//step1: New String()'abc')==1
  //step2 new String('abc'ValueOf () is not a number or a string, then call toString()'[object Object]'==1 //step3: Convert string to number NaN==1 //falseNaN is equal to any type comparisonfalse

  console.log({}==trueStep2 {}.valueof () is neither a number nor a string, then call toString().'[object Object]'==1 //step3: Convert string to number NaN==1 //falseNaN is equal to any type comparisonfalseconsole.log([]==! []) //step1:! If the priority is higher than ==, go to the right first. [] is the object type, which is converted to a Boolean valuetrue,!trueisfalse[] = =false[]==0 // Step3: The left side is an object, valueOf() is not a character nor a string, call toString(), get an empty string' '==0 //step4: Turn the string into a number 0==0 //true
Copy the code

It’s easy to remember the rules: one center (left and right), two basic points (condition: 1). One country, two systems (null, NaN, undefined use one system, other use another system)

Greater than or less than

Let’s take a look at a pit where you’re likely to fall into a knee-jerk thinking trap

 console.log('23'<'3') 
Copy the code

If you get false, then there’s a good chance that you’ve done an implicit conversion in your mind to convert the expression to a number, and the correct result is false. Why? When the string type comparison is large, no type conversion is performed. Instead, ASCII codes are compared bit-by-bit. If the first bit is different, the result is returned; otherwise, the second bit continues to be compared until one bit is different. In the example above, the js engine does the following rules behind the scenes (please ignore that I wrote the variable in two lines, I don’t care about performance here).

var a='23'.charCodeAt(0) //50
var b='3'.charCodeAt(0) //51
50<51 //false
Copy the code

You might say what kind of idiot would write this code, but you don’t know, it’s most likely to happen when the < is left and right variables. Another pitfall involving comparisons is array sorting.

Var a =,10,3,100 [1]. The sort ()Copy the code

You expected the result to be [1,3,10,100], but you were disappointed again because the default comparison rule of sort() converts each element to a string and then compares the ASCII characters of the strings to determine order.

Rule +

The + operator can either add two numbers or concatenate strings, so what happens when [1,2,3]+4? The value on the left of the + sign is called A and the value on the right of the + sign is called B. Step 2: Then see if either A or B is A string, if so, convert the other to A string, and then concatenate step 3: neither A number nor A string, then convert as follows: 1 Can be converted to a number and returns 2. Otherwise, call valueOf() and return it if the result is a primitive type. 3. Otherwise, call toString(), which is returned if the result is an underlying type; 4. If the original value cannot be obtained, throw an exception.