javascript中ToPrimitive详解
July 06, 2017/ Edit on Github ✏️看了这么多框架方面的东西,但注意,基础很重要。今天就来说说 javascipt 中容易忽略的类型转换问题。
在 javascript 中有 7 种基本类型,它们为:string,number,boolean,undefined,null,symbol,object。判断类型的方式是typeof。我们把string,number,boolean,undefined,null,symbol这几类称为原始类型。
typeof 1 // 'number'
typeof "aa" // 'string'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof undefined // 'undefined'
typeof null // 'object'
typeof {} // 'object'
typeof function() {} // 'function'注意两点,一是,对于函数,实际上也可以认为是object,但使用typeof得到的结果是function;二是,对于null,typeof得到的结果是object。
再来看看这些类型之间是怎么转换的呢?今天我们讨论的是object类型转为原始值,对于原始值转为object,可以直接进行包装即可,例如new Number(1),本次不予讨论,本次也不讨论原始类型之间的相互转换。
object 转为 number
先看看下面的几个情况,object转number,输出的值是几多
var obj = {}
console.log(Number(obj)) // NaN
obj = {
valueOf: function() {
return 1
},
}
console.log(Number(obj)) // 1
obj = {
toString: function() {
return 2
},
}
console.log(Number(obj)) // 2
obj = {
valueOf: function() {
return 1
},
toString: function() {
return 2
},
}
console.log(Number(obj)) // 1从上面的例子可以看出,object转为number是根valueOf和toString函数有关的。具体步骤如下:
- 调用对象的
valueOf()方法,如果返回结果是原始类型,则根据这个原始类型再转换为number。 - 否则,调用对象的
toString()方法,如果返回的结果是原始类型,则根据这个原始类型再转换为number。 - 否则,抛出一个异常
TypeError。注意一点的是,symbol转为number时会抛出异常的,null转为number是0。
object 转为 string
我们再来看看下面的例子,输出是几多
var obj = {}
console.log(String(obj)) // "[object Object]"
obj = {
valueOf: function() {
return "a"
},
}
console.log(String(obj)) // "[object Object]"
obj = {
toString: function() {
return "b"
},
}
console.log(String(obj))
;("b")
obj = {
valueOf: function() {
return "a"
},
toString: function() {
return "b"
},
}
console.log(String(obj)) // "b"从上面的例子可以看出,object转为string时也是与valueOf和toString有关,步骤如下:
- 调用对象的
toString()方法,如果返回值是原始类型,则再把这个原始类型转为string - 否则调用对象的
valueOf()方法,如果返回值为原始类型,则再把这个原始类型转为string - 否则,抛出一个异常
TypeError。注意,symbol转为string时会抛出异常。
object 转为 boolean
object转为boolean时总是true,在 javascript 中转为boolean且值为false时只有以下几种值;false,'',0,NaN,undefined,null。
看了这么多,实际上主要是object转number和string时比较复杂,涉及 javascript 中内部的 ToPrimitive 方法。下面为 ecmascript262 中的官方定义:
The abstract operation ToPrimitive takes an input argument and an optional argument PreferredType. The abstract operation ToPrimitive converts its input argument to a non-Object type. If an object is capable of converting to more than one primitive type, it may use the optional hint PreferredType to favour that type.
函数签名为ToPrimitive(input[,PreferredType])=>PreferredType。如果 PreferredType 为 Number,则执行以下步骤:
- 如果 input 是原始值,则返回这个值,结束。
- 否则,如果 input 是对象,则调用
input.valueOf()。如果结果是原始值,则把结果值转为Number。 - 否则,调用
input.toString()。如果结果是原始值,则把结果值转为Number。 - 否则,抛出一个
TypeError。
如果PreferredType是String,则把第二步和第三步进行交换。PreferredType也可以省略的,这种情况下,日期会被认为是String而其他值会被认为是Number。
需要注意的是,每个对象都有默认的valueOf和toString方法,valueOf,toString则根据具体的类型有所区别, 如下:
var obj = {}
console.log(obj.valueOf() === obj) // true
console.log(obj.toString()) // "[object Object]"
obj = [1, 2]
console.log(obj.valueOf() === obj) // true
console.log(obj.toString()) // "1,2"
obj = function() {}
console.log(obj.valueOf() === obj) // true
console.log(obj.toString()) // "function (){}"
obj = new Date()
console.log(obj.valueOf()) // 1497082546564
console.log(obj.valueOf() === obj) // false
console.log(obj.toString()) // "Sat Jun 10 2017 16:15:46 GMT+0800 (CST)"
//......参考
若有收获,小额鼓励