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:
- 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.)
- The original data type is converted to the corresponding built-in Object, while the reference type (Object) remains unchanged
- 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
- ToPrimitive() operation is performed on the left and right sides of + to obtain the original value
- If the raw value obtained contains String, all raw values are concatenated after toString processing
- Everything else is toNumber treated
- 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