preface

Presumably everyone in the interview, often have encountered similar to give you a strange code [] ==! [] let you write the output result of the scene, this time to help you understand js implicit conversion, interview no longer step on the pit

Analysis: Why are there implicit conversions?

If we want to know what implicit conversions are, let’s first understand what explicit conversions are. Okay?

When performing some operations, we will actively change the type of the variable because we need to call the API provided by the corresponding type or perform operations, such as String(),Number(),parsenInt(),toString().. And similar methods, such as the way we manually convert types, called display type conversion

What about implicit type conversions?

JavaScript is weakly typed, which means that unlike strongly typed languages like Java and C++, it does not have predetermined types. In addition, the type of the variable is determined by the type of the value, which leads to a problem. A variable may be String in the previous operation, and Object in the next operation immediately. In order to solve the problem that different types cannot be calculated, JS will convert different types to the same type. The type conversion that the JS runtime environment automatically does for us is called implicit type conversion

JS data type

There are two main types of JS data:

Primitive type: Undefined, Null, String, Number, Boolean, Symbol Reference type: Object

Symbol is newly proposed by ES6, we will not talk about it here

Transformation rules

The ECMAScript runtime system does automatic type conversions when needed. To clarify the semantics of some structures, it is useful to define a set of transformation operators. These operators are not part of the language; They are defined here to assist in the specification of language semantics. Conversion operators are polymorphic – they can accept values of any ECMAScript language type, but not canonical type.

Since the rules are defined by the ES5 specification (see Chapter 9, Type Conversions), there is no need to discuss why, just remember how to use them.

Let’s understand three concepts:

  • Convert to the original value
  • Convert to numbers
  • Convert to string

Because the above documents have a more detailed description, here is only a brief explanation, please refer to the documentation for details

ToPrimitive(convert to original value)

/ * * *@obj Object to be converted *@type The original data type to which you want to convert, optional */
ToPrimitive(obj,type) // This method takes two arguments
Copy the code

Type can be number or string, and the order of execution is somewhat different

String: Call the toString method of Object and return it if it is a primitive value, otherwise call the valueOf method of Object and return it if it is a primitive value, otherwise raise TypeError

Number: Call the valueOf method of Object and return it if it is a primitive value, otherwise call the toString method of Object and return it if it is a primitive value, otherwise raise TypeError

It’s a matter of which method to call, because the expected data type is different, so if it’s a string, it’s a toString call. And vice versa.

And the type parameter can be null, in which case the default value of type is set according to the following rules:

If the object is Date, type is set to String; otherwise, type is set to Number

For the Date data type, we expect more of the string after the conversion time than the millisecond value. If the value is number, the corresponding millisecond value will be taken. Obviously, strings are used more.

For other types of objects, the operation is based on the value type.

In general, ToPrimitive converts to a primitive type depending on type. The type parameter is optional. If specified, it converts to the specified type. When type type is specified, it depends on the following two conversions.

toNumber

The ToNumber method is used in certain cases to convert ToNumber or, if primitive, to the numeric type of the parameter:

Input type The results of
Undefined NaN
Null + 0
Boolean If the argument is true, the result is 1

If the argument is false, the result is +0
Number The result is equal to the input parameter (no conversion)
String The situation is more, refer to the specification
Object In turn, calls

1. Call ToPrimitive (enter type as number)

2. Call ToNumber (original value)

Call Number(); / / call Number(); / / call Number(). Note that ToPrimitive is called first when the parameter is of type Object, and type is number. ToNumber is called after obtaining the original type

toString

The ToString operator converts its arguments ToString values according to the following table:

Input type The results of
Undefined “undefined”
Null “null”
Boolean If the argument is true, the result is “true”

If the argument is false, the result is “false”
Number The situation is more, refer to the specification
String The result is equal to the input parameter (no conversion
Object In turn, calls

1. Call ToPrimitive (type string) to get the original value

2. Call ToString (original value)

Common rules

  • Use Undefined, null, Boolean in quotes, such as ‘null’.
  • Number = “1”, -1 = “-1”, NaN = “NaN”
  • The object is converted to its original value and then processed according to the above steps.

valueOf

When calling the valueOf method, the steps are as follows:

  1. Call ToObject to get an object(In fact, it is the type of packaging, if you are interested, you can learn about it by yourself.)
  2. The original data type is converted to the corresponding built-in Object, while the reference type (Object) remains unchanged
  3. Call the built-in valueOf method of this Object (inherited from the Object.prototype Object)

ValueOf implementations for different built-in objects:

  • String => Returns a String value
  • Number => Returns the Number value
  • Date => returns a number, the time value, and the content of the string is implementation-dependent
  • Boolean => Returns Boolean’s this value
  • Object => Returns this

Implicit conversion: here comes the big bang []==! []

So many concepts mentioned in front, in fact, for you to fully understand, in the calculation of implicit conversion, js exactly do

Example: + operation

  1. ToPrimitive() operation is performed on the left and right sides of + to obtain the original value
  2. If the raw value obtained contains String, all raw values are concatenated after toString processing
  3. Everything else is toNumber treated
  4. ToPrimitive is processed as ToPrimitive Type is Number, except that Date is String
1+'2'+false // '12false'
// Let's break it down:
// Execute from left to right, counting 1+'2'
ToPrimitive() = ToPrimitive(); ToPrimitive() = ToPrimitive()
ToString = '1'+'2'; toString = '12';
// 3. Then repeat step 1 and calculate '12'+false
// 4. Both sides are original values, but '12' is a String, so the Boolean value is also changed to 'false'
// 5. '12'+'false' concatenate result '12false'
Copy the code

Example: Reference type for calculation

var obj1 = {
    valueOf:function(){
        return 1}}var obj2 = {
    toString:function(){
        return 'a'}}// Let's break it down
1+obj1 / / 2
ToPrimitive() = ToPrimitive(); ToPrimitive() = ToPrimitive()
ValueOf (obj1, valueOf, obj1, valueOf, obj1, valueOf, obj1, valueOf, obj1, valueOf, obj1, valueOf, obj1, valueOf, obj1, valueOf
// 3. Add 1 + 1 and print 2
1+obj2 // 1a
ToPrimitive() = ToPrimitive(); ToPrimitive() = ToPrimitive()
Obj2. ValueOf () {obj2. ValueOf () {obj2. Object.prototype.valueOf returns obj2's this, not a primitive value, toString returns 'a'
ToString = '1'+'a'; toString = '1'+'a'
// 4. Create result '1a'
obj1+obj2
// 1. ToPrimitive(); obj1 returns type 1; obj2 returns character type 'a'
ToString = '1'+'a'; toString = '1'+'a';
// select * from '1a';
Copy the code

== = abstract equality comparison

The comparison falls into two categories

  • The same type
  • Different types of

There’s no implicit conversion when the type is the same, so let’s just talk about when the type is different, and the rules are a little bit more complicated here, but just keep in mind one point, when you do the + operation

If the original value obtained containsString, all original values are concatenated after toString processingCopy the code

When you do logical operations, it’s the opposite

If the original value obtained containsString, as far as possibleStringtoNumberType for comparisonCopy the code

Because after all, the expectation of a comparison is a numerical comparison

1. If both types are number, compare them directly

1= =2 // false
// Both sides are numeric types, no implicit conversion
Copy the code

2. If x is string and y is number, x is converted to number for comparison

'0'= =0 // true
If there is a string, return true if the string is converted to a number 0 == 0
Copy the code

3. If a Boolean exists, install toNumber to convert the Boolean to 1 or 0

3= =true // false
// Get the original value, 3 == 1 returns false
'0'= =false // true
// Get the original value, '0' == 0, convert String to Number, 0 == 0 returns true
Copy the code

4. If there are objects, call ToPrimitive to get the original type and compare

var obj = {
    valueOf:function(){
        return '1'}}1 == obj // true
ToPrimitive type = number; obj valueOf (); obj valueOf ()
// 2. The String type is converted to Number
// 3. 1 == 1 于是返回 true[] = =! []// true
// 1.[] as an object ToPrimitive gets ""
/ / 2.! [] = 0; [] = 0; "True" is 1.
// We know that the reference type [] is a pointer to memory. If (memory pointer) is set inversely, return false, which is 0
// 3. "== 0" is found to contain a string, so toNumber is converted toNumber to get 0 == 0 returns true
Copy the code