In the last installment, we learned that there are two big data types in JavaScript: primitive and reference types, and how they are stored (heap and stack).

In this installment, we’ll focus on some of the “weird” issues that arise during JavaScript data type conversions.

Writing in the front

In JavaScript when the operator in the operation, if both sides do not have a unified data, the CPU will not be able to calculate, at this moment we compiler will automatically the data on both sides of the operators to do a data type conversion, converted to the same data type to calculate, this need not programmers manual conversion, the compiler will automatically transform the way is called an implicit conversion.

In JavaScript “Everything is an object”, let’s look at two methods of objects: toString() and valueOf() before we look at implicit conversions in detail.

toString()

The toString() method returns a string representing the object.

// Number to string
(123).toString() / / '123'
// Boolean to string
(true).toString() // 'true'
// Array to string
['hello'.'world'].toString() // 'hello,world'
// Object to string
({name: 'hello world'}).toString() // '[object Object]'
// Date object to string
Date().toString() // 'Wed Jan 23 2019 21:10:42 GMT+0800 (China Standard Time)'
//JSON object to string
JSON.toString() // '[object JSON]'
// Function turns to a string
Function.toString() // 'function Function() { [native code] }'
// Function to string
(function(){ return 1; }).toString() // 'function () { return 1; } '
Copy the code

valueOf()

The valueOf() method returns the original valueOf the specified object.

JavaScript calls the valueOf method to convert the object to its original value. You rarely need to call the valueOf method yourself; JavaScript automatically calls it when it encounters an object with a raw value to expect.

By default, the valueOf method is inherited by every Object after Object. Each built-in core object overrides this method to return the appropriate value. If the object has no original value, valueOf returns the object itself.

Many of JavaScript’s built-in objects have overridden this function to better suit their functional needs. Therefore, the return value and return value type of the valueOf() method for different types of objects may differ.

// The original value of the number
(123).valueOf() / / 123
// The original Boolean value
(true).valueOf() // true
// The original value of the array
['hello'.'world'].valueOf() // [ 'hello', 'world' ]
// The original value of the object
({name: 'hello world'}).valueOf() // { name: 'hello world' }
// The original value of the date object
Date().valueOf() // 'Wed Jan 23 2019 21:10:42 GMT+0800 (China Standard Time)'
// The original value of JSON
JSON.valueOf() // 'Object [JSON] {}'
// the original value of Function
Function.valueOf() // '[Function: Function]'
// The original value of the function
(function func(){ return 1; }).valueOf() // '[Function: func]'
Copy the code

Implicit conversion rules

  1. To string: + (string concatenator)
  2. Into a number types: + + / – (since the increase or the decrement operator), + – * / % (arithmetic operators), > < > = < = = =! = = = =! == (relational operator)
  3. Convert to Boolean:! (Logical non-operator)

String VS plus hyphen

String + primitive = String + String(primitive)

// String + number
console.log('hello' + 123) // 'hello' + '123'
// string + Boolean
console.log('hello' + true) // 'hello' + 'true'
// String + null
console.log('hello' + null) // 'hello' + 'null'
// String + undefined
console.log('hello' + undefined) // 'hello' + 'undefined'
Copy the code

Numbers VS plus hyphens

Number + basic type (non-string) = Number type + Number(basic type)

// number + Boolean
console.log(1 + true) / / 2
/ / is equivalent to
console.log(1 + Number(true)) / / 1 + 1
// number + undefined
console.log(1 + undefined) // NaN
/ / is equivalent to
console.log(1 + Number(undefined)) // 1 + NaN
// Number + null
console.log(1 + null) / / 1
/ / is equivalent to
console.log(1 + Number(null)) / / 1 + 0
Copy the code

Number + reference type = number + reference type.toString ()

// Number + array
console.log(1 + []) / / '1'
/ / is equivalent to
console.log(1 + [].toString()) // 1 + '' = 1
// Number + object
console.log(1 + {}) // '1[object Object]'
/ / is equivalent to
console.log(1 + ({}).toString()) // 1 + '[object Object]'
Copy the code

Number type + Function = Number type + String(function)

// number + function
var func = function() { var a = 2; return 2; }
console.log(1 + func); // 1function () {var a = 2;  return 2;}
Copy the code

Implicit conversion of relational operators

Rule: Compare relationships after converting other data types to numeric types

// String vs Number = Number(string) vs Number
console.log('2' > 10); // flase
/ / is equivalent to
console.log(Number('2') > 10) / / 2 > 10
// String (number) vs string (number) = ASCII (value) vs ASCII (value)
console.log('2' > '10'); // true
/ / is equivalent to
console.log('2'.charCodeAt() > '10'.charCodeAt) / / 50 > 49
// String (letters) vs string (letters) = ASCII (corresponding values) vs ASCII (corresponding values)
console.log('abc' > 'b'); // false
/ / is equivalent to
console.log('abc'.charCodeAt() > 'b'.charCodeAt()) / / 97 > 98
// NaN does not equal NaN
console.log(NaN= =NaN) // false
// undefined vs null
console.log(undefined= =null) // true
// Note: undefined == null does not equal
console.log(Number(undefined) = =Number(null)) // false NaN == 0
// The result of JavaScript's special convention, undefined == null, can be seen in more details
// https://codeburst.io/javascript-null-vs-undefined-20f955215a2
Copy the code

Implicit conversion of logical non – and relational operators

// Number vs array = Number vs Number
console.log([] == 0); // true
/ / is equivalent to
console.log(Number= = ([])0) / / 0 = = 0
// Number vs Boolean = Number vs Number(Boolean)
console.log(! [] = =0); //true
/ / is equivalent to
console.log(Number(! = = [])0) // Number(false) == 0 
// Reference type! = Reference type
console.log([] == []); // false
// Logical non-implicit conversion
console.log([] == ! []);// true
/ / is equivalent to
console.log(Number= = ([])Number(!Boolean([]))) / / 0 = = 0
// Logical non-implicit conversion
console.log({} == ! {});// false
/ / is equivalent to
console.log(Number= = ({})Number(!Boolean({}))) // NaN == 0 
Copy the code

Implicit conversions of reference types

Rules:

  1. When a valueOf() call to a reference type returns a valueOf a primitive type, the operation is performed directly.
  2. When valueOf() of a reference type returns a value other than a primitive type, toString() of a reference type is called and returns the converted string before the operation.
// String + array
console.log('hello' + []) // 'hello' + [].toString()
/ / is equivalent to
console.log('hello' + [].toString()) // 'hello' + ''
// String + object
console.log('hello' + {}) // 'hello[object Object]'
/ / is equivalent to
console.log('hello' + ({}).toString()) // 'hello' + '[object Object]'
Copy the code

Case 1:

Purpose: To verify the implicit conversion process for non-custom objects

// Declare an object obj1
var obj1 = { age: 18 }
console.log(10 + obj1) // '10[object Object]'
Copy the code

Step 1: determine whether the valueOf() return valueOf the object is of a primitive type

console.log(obj1.valueOf()) // { age: 18 }
console.log(typeof obj1.valueOf()) // object returns an object
Copy the code

Step 2: Call toString() on the object and return a string representing the object

console.log(obj1.toString()) // '[object Object]'
Copy the code

Step 3: Perform the operation according to the operation rules (all non-character concatenation operations are converted to Number for operation)

Obj1.tostring () returns a string, so string concatenation is done
console.log(10 + obj1.toString()) // 10 + '[object Object]'
Copy the code

Case 2:

Purpose: To validate the implicit conversion process of an object by customizing valueOf() and toString() of the object

// Declare an object obj2
var obj2 = { 
    age: 18
    toString: function() {
        return ' ' + this.age;   
    },
    valueOf: function() {
        return this.age; }}console.log(10 + obj2) // 10 + 18 = 28
Copy the code

Step 1: determine whether the valueOf() return valueOf the object is of a primitive type

console.log(obj2.toString()) / / '18'
console.log(typeof obj2.toString()) // string
console.log(obj2.valueOf()) / / 18
console.log(typeof obj2.valueOf()) // number
Copy the code

Step 2: Skip to step 3 if the first step returns the basic type correctly, otherwise the object’s toString() call returns a string representing the object

// If valueOf() returns a primitive type
console.log(10 + obj2) // 10 + obj2.valueOf()
// If valueOf() returns a reference type
console.log(10 + obj2) // 10 + obj2.toString()
Copy the code

Step 3: Perform the operation according to the operation rules (all non-character concatenation operations are converted to Number for operation)

// If obj2 returns a string, the string VS plus rule applies
console.log(10 + '18') // 10 + String(obj2)
// If obj2 returns a non-string value, the number VS plus rule applies
console.log(10 + obj2) // 10 + Number(obj2)
Copy the code

Special instructions

There are several special primitive values in JavaScript: null, undefined, ”, 0, NaN.

console.log(typeof null) // object
console.log(null instanceof Object) // false
console.log(NaN= =NaN) // false
console.log(null= =undefined) // true
console.log(Number(null)) / / 0
console.log(Number(undefined)) // NaN
console.log(0= =' ') // true
console.log(0= =' ') // true
console.log(' '! =' ') //true
console.log(null! =0) // true
console.log(undefined! =0) // true
Copy the code

Write in the last

The following conclusions can be drawn from the above implicit conversion of data types in JavaScript:

  1. In JavaScript, operators are converted to the same type (string, number) when they perform an operation.
  2. A String and a plus concatenator are converted to a String
  3. Operations that are not string plus hyphens are converted to the Number type
  4. If valueOf() returns a reference type, toString() is called to return the corresponding string value. In the end, the operation is performed according to the 1, 2, and 3 rules.

Although the above content has been verified, but I do not know whether there is ambiguity in the description, some points are not very clear, hope understanding.

If you find any questions or have better suggestions, please feel free to leave a comment directly to me.

communication

For more exciting content, please pay attention to my Github blog. If you think it is good, please give a star. Thank you very much.