進入正題之前,首先介紹下對象的valueOf()和toString()方法,因爲很多隱式轉換的場景會用到valueOf和toString方法。
每個對象都有這兩個方法。在控制檯輸出Object.prototype,其中就有valueOf和toString方法,而Object.prototype是所有對象原型鏈頂層原型,所有對象都會繼承該原型的方法,故任何對象都會有valueOf和toString方法。js的常見內置對象有:Date, Array, Math, Number, Boolean, String, Array, RegExp, Function。
valueOf方法:
(1)Number、Boolean、String這三種構造函數生成的基礎值的對象形式,通過valueOf轉換後會變成相應的原始值。
var num = new Number('123');
num.valueOf(); // 123
var str = new String('12df');
str.valueOf(); // '12df'
var bool = new Boolean('fd');
bool.valueOf(); // true
(2)Date這種特殊的對象,其原型Date.prototype上內置的valueOf函數將日期轉換爲日期的毫秒的形式的數值。
var a = new Date(); a.valueOf(); // 1515143895500
(3)除此之外返回的都爲this,即對象本身
var a = new Array();
a.valueOf() === a; // true
var b = new Object({});
b.valueOf() === b; // true
toString()方法:
(1)Number、Boolean、String、Array、Date、RegExp、Function這幾種構造函數生成的對象,通過toString轉換後會變成相
應的字符串的形式,因爲這些構造函數上封裝了自己的toString方法。
Number.prototype.hasOwnProperty('toString'); // true
Boolean.prototype.hasOwnProperty('toString'); // true
String.prototype.hasOwnProperty('toString'); // true
Array.prototype.hasOwnProperty('toString'); // true
Date.prototype.hasOwnProperty('toString'); // true
RegExp.prototype.hasOwnProperty('toString'); // true
Function.prototype.hasOwnProperty('toString'); // true
var num = new Number('123sd');
num.toString(); // 'NaN'
var str = new String('12df');
str.toString(); // '12df'
var bool = new Boolean('fd');
bool.toString(); // 'true'
var arr = new Array(1,2);
arr.toString(); // '1,2'
var d = new Date();
d.toString(); // "Wed Oct 11 2017 08:00:00 GMT+0800 (中國標準時間)"
var func = function () {}
func.toString(); // "function () {}"
(2)除以上這些對象及其實例化對象之外,其他對象返回的都是該對象的類型,都是繼承的Object.prototype.toString方法。
var obj = new Object({});
obj.toString(); // "[object Object]"
Math.toString(); // "[object Math]"
接下來就是一些常見的隱式轉換的場景:
1、加法操作符(+)
- 若有一個操作數爲NaN,結果爲NaN
- 若有一個操作數爲字符串,則將另一個數轉換爲字符串然後拼接
- 若有一個操作數爲對象,則調用對象的toString方法再執行上一步
// num: 數值操作數 str: 字符串 obj: 對象
num + 非字符串操作數(NaN/undefined/null/false/true) = num + Number(非字符串操作數)
num + str = 'numstr'; // 1 + 2 + '3' = '33'
str + NaN = 'strNaN'; // '1' + NaN = '1NaN'
str + null = 'strnull'; // '1' + null = '1null'
str + true = 'strture';
obj + num = obj.toString() + num; // Math + 123 = '[object Math]123'
obj + str = obj.toString() + str; // Math + '123' = '[object Math]123'
2、減法操作符(-)
- 若一個操作數爲字符串、null、undefined、布爾值,就調用Number()將其轉換爲數值再運算
- 若一個操作數爲對象則調用該對象valueOf(),沒有valueOf()則調用toString()
1 - '2' = -1;
1 - '123a' = NaN; // 1 - Numer('123a')
1 - Math = NaN; // 1 - Math.valueOf()
1 - true = 0;
3、乘/除法操作符(*、/)
- 若有一個操作數爲NaN,則結果爲NaN
- 若其中一個操作數不爲數字,則調用Number()將其轉換爲數值
2 * '5'; // 10
2 * '5a'; // 2 * Number('5a') -------->
2 * NaN ------------> NaN
4、布爾操作符(!、&&、||)
- 當使用 條件判斷語句(if...else) 以及 布爾操作符(!、&&、||) 時,會調用Boolean()進行隱式類型轉換
- 轉換爲false的有:0, null, undefined, NaN, '', false,其餘都爲true([], {}爲true)
![]; // !Boolean([]); ------------> false
!2; // false
!null; // !Boolean(null); ------------> true
!undefined; // true
!0; // true
if([]) consolo.log('true'); // if(Boolean([])) ... -----------> true
5、關係操作符(>、<、>=、<=)
- 與NaN比較都會返回false
- 若兩個操作數都爲字符串,則比較字符串的編碼值
- 若有一個操作數爲數值,則對另一個操作數用Number()轉換
- 若有一個操作數爲對象,則調用該對象valueOf(),沒有valueOf()則調用toString()
4 > '2'; // true
4 > '2a'; // false
4 > Math; // false
4 > true; // true
'ab' > 'a' // true
6、相等操作符(==、!=)
- 字符串、布爾類型和數值比較,現將前者用Number()轉換爲數值
- 若一個操作數是對象另一個不是,則調用該對象valueOf(),沒有valueOf()則調用toString()
- 若兩個操作數都是對象,則比較它們是不是同一個對象(地址是否相同)
- null和undefined是相等的
- null和undefined不會轉換成任何值
- 任何數都不等於NaN,包括NaN自己
//特例:
NaN == NaN//false //NaN是唯一不等於自身的
// true
'123' == 123
[123] == 123
true == '1'
1 == true
'1' == true
'123' == new String(123);
null == undefined;
// false
2 == true
'2' == true
null == 0;
new String(123) == new String(123);
7、全等操作符(===、!==)
- 全等操作符不會轉換操作數
123 === '123'; // false
null === undefined; // false