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}]