Implicit conversions are “explicit” conversions to you, if you’ve mastered them thoroughly.

Small class the teacher

  • Type conversion rules
  • Unary operator
  • The additive operator
  • Multiplicative operator
  • Boolean operator
  • Equality operator
  • Relational operator
  • Other operators
  • Incredible example
  • conclusion

Type conversion rules

JS is a weakly typed language and can be converted between different data types.

There are only three types of conversion in JS: toString, toNumber, and toBoolean. The normal conversion rules are as follows:

| original value/type | target type: Number results | | | | – | | – | | null | number | 0 | | symbol | number | thrown fault | | string | number | ‘1’ = > 1 ‘1 a = > NaN, Contains non-numeric is NaN | | | array number | [] = > 0 (‘ 1 ‘) = > 1 (‘ 1 ‘, ‘2’) = > NaN | | object/function/undefined | number | NaN |

Original value/type | | target type: string results | | | | – | | – | | number | string | 1 = > ‘1’ | | array | string | [1, 2] = > ‘1, 2,’ | | Boolean value/function/symbol | string | original value with quotes, such as: ‘true’ ‘Sumbol()’| |object|string|{}=>'[object Object]’|

| original value/type | target type: A Boolean result | | | | – | | – | | number | Boolean | in addition to 0, NaN is false, everything else is true | | string | Boolean | in addition to an empty string to false, Everything else is true | | null/undefined | Boolean | false | | reference type | Boolean | true |

Implicit type conversions are implemented by the following abstract operations:

ToString

The abstract operation ToString handles implicit type conversions from non-strings to strings. When the string form of a value is required, a ToString conversion is performed.

The String() function performs the abstract ToString operation, following the following conversion rules:

  1. If the value is a primitive type, it is converted directly to a string. If it is a reference type, the ToPrimitive abstraction is performed.
  2. If the value is null, “null” is returned;
  3. If the value is undefined, return “undefined”.
String(a)/ /"
String(0)   / / '0'
String(true)  // 'true'
String(null)  // 'null'
String(undefined)  // 'undefined'
String(Symbol('asdf'))  // "Symbol('asdf')"
String({})  // '[Object object]'
// the default toString() method for arrays has been redefined toString all cells together with ","
String([])  / /"
String([1.2.3.4.'asdf'])  / / '1, 2, 3, 4, asdf'
Copy the code

ToNumber

The abstract operation ToNumber handles non-numeric to numeric implicit type conversions.

Number() performs the abstract operation ToNumber, which is converted as follows.

  1. If Boolean, true and false are converted to 1 and 0, respectively.
  2. If it is a numeric value, it is simply passed in and returned.
  3. If it is null, 0 is returned.
  4. If undefined, NaN is returned.
  5. If it is a string: If the string is empty (containing no characters), it is converted to 0; If it contains a non-number, it is converted to NaN.
  6. If it is an object, perform the ToPrimitive abstraction, return the basic type and follow the above rules.
Number(a)/ / 0
Number(' ')  / / 0
Number(' ')  / / 0
Number('0')  / / 0
Number('asdf')  // NaN
Number(true)  / / 1
Number(false)  / / 0
Number(null)  / / 0
Number(undefined)  // NaN is different from null
// The object is converted to a primitive type by the abstract operation ToPrimitive, and then to a number
Number({})  // NaN
Number([])  / / 0
Number([' '])  / / 0
Number([' '])  / / 0
Number(['0'])  / / 0
Number([1.2])  // NaN
Copy the code

ToBoolean

The abstract operation ToBoolean handles implicit type conversions from non-Booleans to Booleans.

Casting to Boolean is the easiest. The conversion rules are as follows:

(1) values that can be cast to false

  • undefined
  • null
  • false
  • +0, -0, and NaN
  • “”

(2) Other values will be cast to true

ToPrimitive

The abstract operation ToPrimitive is used to convert a reference type to a primitive type. The built-in Symbol. ToPrimitive function is used to convert the reference type to the original type, and can also be customized to the object as follows. Implementation details are more complex, interested in children’s shoes can refer to here.

// Simulate the ToPrimitive operation of an object
var o = {};
o[Symbol.toPrimitive] = function(hint) {
  console.log(hint) //hint string one of string number default
  if (hint == "default" || hint == "number") {
    if (o.valueOf && typeof(o.valueof()) ! ='object') {
      return o.valueOf()
    } else {
      return o.toString()
    }
  } else {
    if (o.toString && typeof(o.toString()) ! ='object') {
      return o.toString()
    } else {
      return o.valueOf()
    }  
  }
}
String(o) // string
Number(o) // number
1+o // default
1-o // number
o++ // number
++o // number
Copy the code

ToPrimitive conversion rules are as follows:

  1. If the passed argument isstring(This order is currently only performed when calling String()) : First check if the value has a toString() method. If a primitive type value is present and returned, that value is used for the cast. If not, check to see if the value has a valueOf() method. If a primitive type value is present and returned, the return value is used for the cast. If no primitive type value is present or not returned, an error is thrown.
  2. If the passed argument isnumber/default(Common casts are in this order) : First check if the value has a valueOf() method. If a primitive type value is present and returned, that value is used for the cast. If not, check to see if the value has a toString() method. If a primitive type value is present and returned, the return value is used for the cast. If no primitive type value is present or not returned, an error is thrown.

Unary operator

Here’s the concept: js operators and operands make up expressions that must return a value. Both unary + + a operation, and Boolean operations [] | | false, will return a value. See MDN’s: Operator Priority for additional information on JS operator priority.

Unary operators are operators that operate on only one value, as opposed to additive operators that operate on two values (e.g., a + b).

// Suppose there is a variable a
+a // Unary add operator
-a // Unary subtraction operator
++a // Pre-increment operator
--a // The pre-decrement operator
a++ // The post-increment operator
a-- // The post-decrement operator
Copy the code

1. Unary addition and subtraction operators

The unary plus operator + is used for non-numeric casts equivalent to Number(). Such as:

+'1.1' / / 1.1
+'asdf' // NaN
+true / / 1
+false / / 0
+null / / 0
+undefined // NaN+ {}// NaN+ []/ / 0
+new Date(a)/ / 1556258367546
Copy the code

The unary subtraction operator – behaves like +, except that the final result is a negative number. If -true, the result is -1.

2. Increment decrement operator

Unlike the unary addition and subtraction operators, the incrementing and decrement operators operate only on the number type. Throw an error if used for any other type.

// preincrement
var a = 57;
var b = ++a;
console.log(b); / / 58
// postincrementing
var a = 57;
var b = a++;
console.log(b); / / 57
Copy the code

The difference between pre-increment and post-increment is that the pre-increment ++a returns an incremented value of 1, while the post-increment A ++ does not. Decrements and increments are the same, no more nonsense.

The additive operator

1. Add operator+

The + operator is commonly used for mathematical calculations and concatenation of strings as follows:

  1. If both operators are numeric, normal addition is performed
  2. If one of the operands is NaN, the result is NaN;
  3. If both operands are strings, concatenate the second operand with the first;
  4. If only one operand is a string, the other operand is converted to a string, and then the two strings are concatenated.
  5. If one of the operands is an object, the return valueOf the abstract ToPrimitive (valueOf then toString) operation is performed, and the previous rules for strings are applied.
  6. For undefined and null, call String() and get the strings “undefined” and “null”, respectively.
1+1 / / 2
NaN+1 // NaN
'asdf'+'ghjk' // 'asdfghjk'
1+1+'1' / / '21'[] +1 / / 1
null+undefined // 'nullundefined'[] + + {}1 // '[Object Object]1' Actual execution: ''+'[Object Object]'+1{} + + []1 // 1 {} at the beginning of the line is interpreted as a code block, the code block is ignored here, so the actual execution: +[]+1, resulting in the number 1
Copy the code

2. Subtraction operators-

  1. If both operators are numeric, normal addition is performed
  2. If one of the operands is NaN, the result is NaN;
  3. If one of the operands is a string, Boolean, null, or undefined, the Number() function is called behind the scenes to convert it to a value, and then subtraction is performed according to the previous rules. If the result of the transformation is NaN, then the result of the subtraction is NaN;
  4. If one of the operands is an object, the abstract operation ToPrimitive is performed, calling the valueOf() method of the object first to get the value representing the object. If the value is NaN, the result of subtraction is NaN. If the object has no valueOf() method or returns a value other than a primitive type, its toString() method is called and the resulting string is converted to a numeric value.
1-1 / / 0
NaN-1 // NaN
10-true-null / / 9
10-true-undefined // NaN[] -1 / / 0
['11'] -11 / / 0
11- {}// NaN
Copy the code

Multiplicative operator

The multiplicative operators include multiplication *, division /, and division mod %. Here are the rules:

  1. If both operators are numeric, perform conventional multiplication and division modulo.
  2. If one of the operands is NaN, the result is NaN;
  3. If one of the operands is not a value, call Number() in the background to convert it to a value, and then apply the above rules.

The numerical calculation is special as follows:

Infinity*0 // NaN
Infinity/Infinity // NaN
0/0 // NaN
Infinity%a // NaN a is an arbitrary value
a%0 // NaN a is an arbitrary value
Copy the code

Boolean operator

1. The logic!

The logical nonoperator converts any value to a Boolean value, as opposed to the Boolean() function. Using two logical non-operators in a row is equivalent to calling Boolean(). Common Daniel write code!! IsTrue instead of Boolean(isTrue) functions.

!undefined // true!!!!!undefined // false
!NaN // true!!!!!NaN // false
!1234 // false!!!!!1234 // true
!' ' // true!!!!!' ' // false
Copy the code

2. Logic or||

Short-circuit operation: If the first operand determines the result, the second operand is not evaluated.

The logic or operator is short-circuited. If the evaluation of the first operand (Boolean evaluation, same below) is true, the first operand is returned and the second operand is not evaluated. If the first operator is false, the second operand is returned. Therefore, the common great god write code isExist | | getIsExist (), is the use of short circuit operation, if isExist evaluates to true, no longer perform getExist () function.

[] | |0 // [] objects (arrays, functions, etc.) always evaluate to 'true' and return the object directly
0| | []/ / []
1| | []/ / 1
NaN || 0 / / 0
Copy the code

And (3) logic&&

Logic and operations are short-circuited operations, that is, if the first operand evaluates to false, the first operand is returned and the second operand is not evaluated. The second operand is returned if the first operand evaluates to true. Can be used to condition obj && obj.value. Obj. Value is taken only if the obj object exists.

0 && true / / 0
null && [] // null
NaN && null // NaN
[] && {} / / {}
Copy the code

Note that Boolean operators have precedence:! > & > | | :

null || !2 || 3 && 4 / /???????? Do you know the result? In effect, the code is equivalent to the following line
null| | (!2) | | (3 && 4) / / 4
Copy the code

Equality operator

The equality operator has ==! = = = =! == four, where equal and unequal implement type conversion before comparison, and congruent and incongruent implement only comparison without type conversion. The equality operator returns a Boolean value true or false.

1. Equality and inequality

The comparison rules for operands of different types are as follows:

  • Check whether null and undefined are being compared, and return true if so. Null and undefined are not equal to any other value.
  • Check whether the two types are string and number. If so, the string is converted to number.
  • Check whether one of the two parties is Boolean. If yes, the Boolean will be converted to number.
  • Check whether one of the objects is object and the other is string, number, or symbol. If so, the object is converted to its original type.
[] = =! []// true
/* * First, the Boolean operator! Second, the operand has a Boolean value false, which is converted to a number: [] == false * [] == 0 * again, the operand [] is an object and is converted to the primitive type (valueOf() is the same as [] and toString() is the empty string) : "== 0 * Finally, the string is compared to a number and converted to a number: 0 == 0 */
NaN= =NaN // false NaN does not equal any value
null= =undefined // true
null= =0 // false
undefined= =0 // false
Copy the code

Congruence and incongruence

Congruence and incongruence do not convert types before comparison, so it is relatively simple:

null= = =undefined // false
'1'= = =1 // false
0= = =false // false[] [] = = =// False reference types are equal depending on whether they refer to the same memory address
NaN= = =NaN // False NaN is special and not equal to itself
Copy the code

Relational operator

The relational operators less than (<), greater than (>), less than or equal to (<=), and greater than or equal to (>=) compare the size of two values and return a Boolean value. A conversion occurs when one of the operands is non-numeric:

  1. If both operands are numeric, a numeric comparison is performed.
  2. If both operands are strings, the character encoding values of the two strings are compared.
  3. If one operand is a value, the other operand is converted to a value, and a numeric comparison is performed.
  4. If an operand is an object, ToPrimitive is converted to a primitive type (valueOf followed by toString).
  5. If an operand is a Boolean, it is converted to a numeric value before the comparison is performed.
'23' <'3' // true compares character encoding values
'23' < 3 // false Executes rule 3
NaN > 0 // false NaN comparisons always return false
null> =0 // true executes rule 3, noting that null equality comparisons are not the same as relational comparisons
undefined> =0  //false undefined performs a relational comparison to NaN, always returning false

Copy the code

Conditional operator

1. Conditional operators

A ternary expression is defined by the conditional operator? : :

a > b ? a : b;  / / if? If the previous operation evaluates to true, return a, otherwise return b
Copy the code

2. The assignment operator

Var a = 1 assigns the value 1 to variable A. Can compound with + – * / % :

a += b // a = a + b
a -= b // a = a - b
a *= b // a = a * b
a /= b // a = a/b
a %= b // a = a % b
Copy the code

3. Comma operator

The comma operator is often used to declare multiple variables in a single statement: var a = 1, b = 2, c;

4. Bit operators

Js values are stored in 64-bit format. The first 32 bits are integers and the last 32 bits are decimals. Bitwise operators convert 64-bit values to 32-bit values, so bitwise operators force floating point numbers to integers. Here are a few common bit operators:

  1. An operator~:~xThe equivalent of-(x+1)Can be used instead ofindexOfAs a condition of judgment.~str.indexOf('asdf')The equivalent ofstr.indexOf('asdf')>-1;
  2. An operator|: can be used to cut a value into a 32-bit integer.1.11 | 0The result of the execution is1

Incredible example

  1. Please listen to:
var a = { n: 1 }
var b = a
a.x = a = { n: 2 } // What is the variable b?
Copy the code

I bet you fainted, too. This example examines two knowledge points of operator priority/reference type assignment:

In the second sentence, a and B refer to the same memory address 1.

A.x = (a = {n: 2}) a.x = (a = {n: 2}) So at this time, a.x = opens a new attribute x in memory address 1, which points to the return value of the expression in parentheses {n: 2}.

Finally, the expression in parentheses (a = {n: 2}) reassigns the variable a to {n: 2}. At this point, variable A and variable B have been split, and variable B still points to the original address 1, while variable A creates a new object {n: 2} and is assigned to attribute X in address 1 as the result of expression, that is, B.x. So the value of the final object B is {n: 1, x: {n: 2}}, and b.x === a is true.

  1. Please listen to:
('b'+'a'+ + 'a'+'a').toLowerCase() === 'banana' // ?
Copy the code

This is just saw yCK big guy’s article in the question, very embarrassed I unexpectedly answer wrong, I thought the answer is to throw wrong ~~

+ + ‘a’ converts string A to NaN, concatenates NaN with string (confusing additivity between string and value), and throws an error when calling toLowerCase()

The concatenation of NaN and string results in ‘baNaNa’, not NaN.

conclusion

JS type conversions are a headache, but they are not untraceable. With some practice and knowledge of the conversion rules, you can figure out exactly how and to what types will be converted.