JS 中的類型
JS中的類型分爲兩大類: primitive和object。
primitive: null, undefined, Number, String, Boolean, Symbol。
object:不是primitive類型的值,都是object類型。
JS是非嚴格類型的語言
在JS中存在大量的數據隱式轉換,例如 1 + 'a'
。對於primitive類型,在不同類型之間有明確的轉換規則:
Number
Number(null) // 0
Number(undefined) // NaN
Number(false) // 0
Number(true) // 1
Number('123') // 123
Number('123a') // NaN
Number('') // 0
Number(Symbol('1')) // TypeError
String
非常直接,將字面量形式直接轉換成字符串形式的字面量
String(null) // 'null'
String(undefined) // 'undefined'
String(NaN) // 'NaN'
String(1) // '1'
String(Symbol('a')) // 'Symbol(a)'
Boolean
Boolean(null) // false
Boolean(undefined) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
/* 其餘情況均爲true */
Boolean('a') // true
Boolean(Symbol('foo')) // true
如果是類型轉換涉及到object類型呢
primitive轉成object
將primitive類型轉成object類型都有對應的構造函數。
Number(1)
String('foo')
Boolean(true)
將object轉換成primitive
在ECMAScript文檔,爲object定義了一個內部方法toPrimitive
。它類似於下面的形式
toPrimitive(target, PreferredType?)
target表示需要轉換的對象,PreferredType參數可選,標明想要轉成的類型,string 或 number。
轉換步驟:
- 如果沒有定義PreferredType, 則默認爲’default’;
- 如果存在自定義的toPrimitive方法,就返回執行自定義toPrimitive方法的結果;
- 如果PreferredType 的值爲’default’,默認選擇爲
number
; - 返回系統默認toPrimitive方法的執行結果;
如果執行系統默認的toPrimitive方法,
在輸入對象是object,且 PreferredType的值爲’string’,則優先執行toString方法,沒有則執行valueOf方法。
如果PreferredType的值爲’number’,則優先執行valueOf方法,沒有valueOf方法則執行toString方法。
js中的操作符大部分都是針對primitive類型設計的,如果用這些操作符對object類型進行處理運算,會將object類型先轉成primitive類型的值,然後在進行運算操作。
+[12] // 12
+({}) // NaN
[]==0 // true
{}==0 // false
上述情況走的都是對象自身默認的toPrimitive方法且未指定PreferredType值。
還有一種情況是我們自定義對象的valueOf和toString方法。
var o = {
value:1,
toString:function(){
console.log('toString');
return 'one';
},
valueOf: function(){
console.log('valueOf');
return this.value++;
}
}
alert(o); // 'one'
console.log(o == 1); // true
console.log(o == 2); // true
對象默認的toString和valueOf方法
這兩個方法都在Object.prototype上面。valueOf默認返回對象自身,如果操作對象是基本類型,則只返回一個基本值。怎麼理解這句話呢?
(1).valueOf() // 1
var n = new Number(1);
n.name="number";
console.log(n);
var m = n.valueOf();
var o = { name: 'object'};
var p = o.valueOf();
console.log(m);
console.log(p);
toString的返回值就比較
ES6中的Symbol.toPrimitive
var o = {
value:1,
[Symbol.toPrimitive]: function(hint){
console.log('Symbol.toPrimitive');
if(hint === 'number' || hint === 'default') return this.value+=2;
return 'toprimitive function';
},
toString:function(){
console.log('toString');
return 'one';
},
valueOf: function(){
console.log('valueOf');
return this.value++;
}
}
alert(o); // 'toprimitive function'
console.log(o == 1); // false
console.log(o == 5); // true
ToPrimitive 定義(https://www.ecma-international.org/ecma-262/6.0/#sec-toprimitive)
Data類型的toPrimitive
toPrimitive中還存在另外一個特殊情況。Date類型的對象在執行toPrimitive方法時,PreferredType的默認值爲’string’,而非’number’。
下面例子中,明顯表明 Date類型在執行 +1
操作時,先轉成字符串再進行運算; 而普通對象則是先執行valueOf方法,再進行運算;
var d = new Date;
var o = {
value: 1,
valueOf: function(){ return 2;},
toString: function(){ return 'tostring';}
}
d+1;// "Sun Dec 15 2019 21:56:35 GMT+0800 (中國標準時間)1"
o+1; // 3
d.toString=function(){return 'date toString';}
console.log(d); // "date toString"
d+1;// "date toString1"
Summary
valueOf
和toString
是JS中類型轉換中處理object類型的重要組成。
在未自定義的情況下,這兩個方法都在Object.prototype上。 valueOf通常返回對象本身,而toString會根據對象的internal slot
返回數據格式如下[object ${Type}]