Wang Li, the author of this article, is a senior front-end engineer of New Oriental Online, mainly responsible for the design and development of user transaction, user growth and other related systems.

Before the body begins, look at this code:

[] = =! []// ?
{} == ! {} // ?
Copy the code

What is this? Meng…

I think it’s a cast.

Come on, don’t be confused, read the following article, you will understand.

Cast casting

Number()

Parameter is primitive type

// Value: the original value after conversion
Number(123) / / 123

// String: If it can be parsed to a numeric value, it is converted to the corresponding numeric value
Number('123') / / 123

// String: If it cannot be parsed as a number, return NaN
Number('123abc') // NaN

// The empty string is converted to 0
Number(' ') / / 0

// Boolean values: true to 1, false to 0
Number(true) / / 1
Number(false) / / 0

// undefined: becomes NaN
Number(undefined) // NaN

// null: converts to 0
Number(null) / / 0
Copy the code

Number() converts a string to a Number, stricter than the parseInt function. Basically, if a single character cannot be converted to a numeric value, the entire string is converted to NaN. However, parseInt can handle string interception and numeric notation:

parseInt('32 abc') / / 32
parseInt('0x11 abc') / / 17

Number('32 abc') // NaN
Number('0x11 abc') // NaN
Copy the code

Parameter is object

When Number() takes an object, it is almost always converted to NaN, except for an array containing a single value.

Number({ a : 1 }) // NaN
Number([ 1.2.3 ]) // NaN
Number([ 5 ]) / / 5
Copy the code

Why is that? What the hell happened?

Let’s start with this code:

const obj = {
  toString: function() {
    return 1;
  },
  
  valueOf: function() {
    return 2; }};console.log(Number(obj));  / / 2
Copy the code

Number(obj) Invokes the valueOf method. The output is 2. Make some changes to the code above:

const obj = {
  toString: function() {
    return 1;
  },
  
  valueOf: function() {
    return{}; }};console.log(Number(obj)); / / 1
Copy the code

The result is 1, and Number(obj) calls the toString method. Now look at the following code:

const obj = {
  toString: function() {
    return {};
  },
  
  valueOf: function() {
    return{}; }};console.log(Number(obj)); / / an error
Copy the code

Uncaught TypeError: Cannot convert object to primitive value What if I delete the toString method?

const obj = {
  valueOf: function(){
    return{}; }};console.log(Number(obj)); // NaN
Copy the code

In the above code, Number({}) calls the default toString method, the toString method on Object.prototype. The specific process is shown in the following code:

/ / dismantling Number ({})

Object.prototype.toString.call({}) // "[object Object]"
Number("[object Object]") // NaN
Copy the code

In the example above, valueOf returns an object. Let’s look at how it returns an array.

const obj = {
  valueOf: function(){
    return[]; }};console.log(Number(obj)) / / 0
Copy the code

In the above code Number(obj) is equivalent to Number([]), which calls Array’s toString method instead of Object’s toString. As follows:

/ / dismantling Number ([])

Array.prototype.toString.call([]) / / ""
Number(' ') / / 0
Copy the code

Then look at the Object. The prototype. ToString:

Object.prototype.toString.call([]) //'[object Array]'
Number('[object Array]') // NaN 
Copy the code

When Number() takes an object type, the following conclusions can be drawn:

  1. Calls the valueOf method of the object itself. If a value of the original type is returned, the Number function is used directly on the value without further steps.

  2. If the valueOf method still returns an object, the toString method of the object itself is called instead. If the toString method returns a value of the original type, the Number function is used on the value without further steps.

  3. If toString returns an object, an error is reported.

Object. The prototype. ToString return values:

  // Primitive type
  Object.prototype.toString.call('123') // '[object String]'
  Object.prototype.toString.call(123) // '[object Number]'
  Object.prototype.toString.call(NaN) // '[object Number]'
  Object.prototype.toString.call(Infinity) // '[object Number]'
  Object.prototype.toString.call(null) // '[object Null]'
  Object.prototype.toString.call(undefined) // '[object Undefined]'
  
  // Reference type
  Object.prototype.toString.call(function() {}) // '[object Function]'
  Object.prototype.toString.call([1.2.3]) // '[object Array]'
  Object.prototype.toString.call([1]) // '[object Array]'
  Object.prototype.toString.call({}) // '[object Object]'

  Object.prototype.toString.call(new Error()) // '[object Error]'
  Object.prototype.toString.call(/\d/) // '[object RegExp]'
  Object.prototype.toString.call(Date()) // '[object String]'
  Object.prototype.toString.call(new Date()) // '[object Date]'
  Object.prototype.toString.call(Symbol()) // '[object Symbol]'
  
  // Provided by the browser
  (function (){
    Object.prototype.toString.call(arguments) // '[object Symbol]'}) ()Object.prototype.toString.call(document) // '[object HTMLDocument]'
  Object.prototype.toString.call(window) // '[object Window]'
Copy the code

String()

Parameter is primitive type

When String() takes a primitive data type:

  • Value: Converts to the corresponding string
  • String: the original value after conversion
  • Boolean values: true to string ‘true’, false to string ‘false’
  • Undefined: converts to string ‘undefined’
  • Null: Converts to string ‘null’

A code example is as follows:

String(123) / / "123"
String('abc') // "abc"
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null"
Copy the code

Parameter is object

When String() takes an object type:

String({ a: 1 }) // "[object Object]"
String([1.2.3]) / / "1, 2, 3"
Copy the code
const obj = {
  toString: function() {
    return 1;
  },
  valueOf: function() {
    return 2; }};console.log(String(obj)) / / 1
Copy the code

String() has the same conversion rules as Number(), except that valueOf and toString methods are executed in the same order.

  1. We call the toString method of the object itself. If a value of the original type is returned, the String function is used for that value and the following steps are not performed.

  2. If the toString method returns an object, call the valueOf method of the original object. If the valueOf method returns a valueOf the original type, the String function is used for that value and the following steps are not performed.

  3. If valueOf returns an object, an error is reported.

Different types of toString methods have different results:

[1.2].toString() === Array.prototype.toString.call([1.2]) // true

Array.prototype.toString.call([1.2= =])Object.prototype.toString.call([1.2]) // false
Copy the code

Boolean()

Falsey (imaginary)

When a Boolean type is converted, an imaginary value is converted to false. There are several types of imaginary values:

undefined
null
0 / / + 0-0
NaN 
false 
' ' 
Copy the code

Other situations

All but imaginary values are true:

Boolean([]) // true
Boolean({}) // true
Boolean(new Error()) // true
Boolean(Symbol()) // true
Copy the code

Implicit type conversion/automatic conversion

Automatically converts to a Boolean value

These symbols are automatically converted to Boolean values:

if(a)for while switch! !!!!! = = =? : && | |Copy the code

Implicit type conversion: All but imaginary values are converted to true

Automatically converts to a string

Automatic conversion of strings occurs mainly during string addition operations. When one value is a string and the other is a non-string, the latter is converted to a string.

'5' + 1 / / '51'
'5' + true // "5true"
'5' + false // "5false"
'5' + {} // "5[object Object]"
'5' + [] / / "5"
'5' + function (){} // "5function (){}"
'5' + undefined // "5undefined"
'5' + null // "5null"

null+ []?null+ {}?null + funciton() {}
Copy the code

Automatically converts to a value

Except for the addition operator (+), which may convert operands to strings, all arithmetic operators automatically convert operands to numbers.

'5' - '2' / / 3
'5' * '2' / / 10
true - 1  / / 0
false - 1 // -1
'1' - 1   / / 0
'5' * []    / / 0
false / '5' / / 0
'abc' - 1   // NaN
null + 1 / / 1
undefined + 1 // NaN
Copy the code

Note: null is 0 when converted to a value, and undefined is NaN when converted to a value.

In positive/negative sign operators:

+'abc' // NaN
-'abc' // NaN
+true / / 1
-false / / 0
Copy the code

Relational operators such as ==! ==, will also be converted to a number.

1= =true // true
'1'= =true // true
'1'= =1 // true
[1] = =1 // true
[1] = =true // true[] = =false // true[] = =null // false
[1.2] = =NaN // false
Copy the code

Special values

Infinity

Number(Infinity) //Infinity
1 / 0= =Infinity // true
1 / Infinity= =0 // true
Infinity= = =Infinity // true
Infinity= = = -Infinity // false
0= = = -0 // true
0 / 0 // NaN
Copy the code

NaN

NaN= =NaN // false
Copy the code

Undefined and null

null= = =null // true
undefined= = =undefined // true

undefined= =null // true
undefined= = =null // false
Copy the code

conclusion

Now let’s answer the question we started with.

The first is [] ==! [] is true, as shown below:

[] ==! []

[].toSring() / /"
Number(' ')   / / 0! []// false
Number(false) / / 0

0= =0  / / [] = =! [] to true
Copy the code

The {} = =! {} is false, as shown below:

{} ==! {}

({}).toString() // "[object Object]";
Number("[object Object]") // NaN! {}// false
Number(false) / / 0

NaN! =0 / / {} = =! {} to false
Copy the code

So what does the following code output?

{} + {} // ?
[] + {} // ?
{} + [] // ?
Copy the code

You can try it out by clicking on this link.


Search ikoofe on wechat, and the public account “KooFE Front-end team” releases front-end technology articles from time to time.