无论是Number(obj)、还是String(obj),如果obj[Symbol.toPrimitive]方法存在的话,都会先调用obj[Symbol.toPrimitive]方法,如果Symbol.toPrimitive方法返回的不是基本类型数据,直接报错!!!如果没有定义该方法才会按照下面的情况走:
- Number(obj)会优先调用valueOf方法,如果返回的不是基础数据类型,则继续调用toString方法,如果toString方法也返回的不是基础数据类型,则报错。
- String(obj)会优先调用toString()方法,如果返回的不是基础数据类型,则继续调用valueOf方法,如果valueOf方法也返回的不是基础数据类型,则报错。如果没有定义toString方法(即使定义obj.toString = null也算定义了),即使定义了valueOf方法,valueOf方法不会调用,直接返回[object object]。
使用对象(函数,obejct)进行运算或者console.log(fn),会优先调用valueOf()方法,如果valueOf返回的不是基本数据类型(字符串,数字,布尔值),则会调用toString方法,如果toString方法也不返回基本数据类型,则会报错。
.0
var obj = {
toString: function() {
console.log('toString')
return 6
},
valueOf: function() {
console.log('valueOf')
return 5
}
}
/*
* 先调用valueOf,再调用toString方法。
* 如果只显式定义了toString方法也会调用toString方法。
*/
console.log(obj + 1) // valueOf 6
console.log(Number(obj)) // valueOf 5
console.log(String(obj)) // toString 6
obj = {
toString: function() {
console.log('toString')
return 6
}
}
console.log(obj + 1) // toString 7 没有定义valueOf,也会调用toString
obj = {
valueOf: function() {
console.log('valueOf')
return 5
}
}
console.log(String(obj)) // [object object] 根本不会调用valueOf方法
//使用对象进行运算,会优先调用valueOf方法
let fn = function(){
}
fn.toString = function(){
return 5
}
fn.valueOf = function(){
return 6
}
console.log(1+fn) // 7 先调用valueOf
console.log(Number(fn)) // 6
console.log(String(fn)) // 5
ToString
null:转为”null”
undefined:转为”undefined”
布尔类型:true和false分别被转为”true”和”false”
数字类型:转为数字的字符串形式,如10转为”10”, 1e21转为”1e+21”,1e10转为”10000000000”
数组:转为字符串是将所有元素按照”,”连接起来,相当于调用数组的Array.prototype.join()方法,如[1, 2, 3]转为”1,2,3”,空数组[]转为空字符串,数组中的null或undefined,会被当做空字符串处理
普通对象:转为字符串相当于直接使用Object.prototype.toString(),返回”[object Object]“,前提是没有重写默认的toString方法
String(null) // 'null'
String(undefined) // 'undefined'
String(true) // 'true'
String(10) // '10'
String(1e21) // '1e+21'
String([1,2,3]) // '1,2,3'
String([]) // ''
String([null]) // ''
String([1, undefined, 3]) // '1,,3'
String({}) // '[object Objecr]'
ToNumber
null: 转为0
undefined:转为NaN
字符串:如果是纯数字形式,则转为对应的数字,空字符转为0, 否则一律按转换失败处理,转为NaN
布尔型:true 和 false 被转为 1 和 0
数组:数组首先会被转为原始类型,即ToPrimitive默认先调用valueOf方法,如果返回的不是原始类型,继续调用toString方法。可以这样理解:Number([1]) => Number(‘1’) => 1;Number([1,2]) => Number(‘1,2’) => NaN。空数组返回 0
对象:同数组的处理
Number(null) // 0
Number(undefined) // NaN
Number('10') // 10
Number('10a') // NaN
Number('') // 0 注意这个
Number(true) // 1
Number(false) // 0
Number([]) // 0 注意这个, 先把数组转基本数据类型(先调用valueOf,如果返回的不是基本类型,再调用toString),
Number(['1']) // 1
Number({}) // NaN
ToBoolean
js中的假值只有false、null、undefined、空字符、0和NaN,其它值转为布尔型都为true。
Boolean(null) // false
Boolean(undefined) // false
Boolean('') // flase
Boolean(NaN) // flase
Boolean(0) // flase
Boolean([]) // true
Boolean({}) // true
Boolean(Infinity) // true
ToPrimitive
对象类型类型(如:对象、数组)转换为原始类型的操作。
当对象类型需要被转为原始类型时,会首先调用 [Symbol.toPrimitive] 方法,该方法必须返回原始类型值,否则会直接报错。注意这里不会再去调用 valueOf 或 toString 方法。
如果没有 Symbol.toPrimitive 方法,则会先调用该对象的 valueOf 方法,如果 valueOf 方法返回原始类型的值,则 ToPrimitive 的结果就是这个值。
如果 valueOf 不存在或者 valueOf 方法返回的不是原始类型的值,就会尝试调用对象的 toString 方法,也就是会遵循对象的 toString 规则,然后使用toString的返回值作为 ToPrimitive 的结果。如果两个返回都不是原始类型则报错。
注意:对于不同类型的对象来说,ToPrimitive 的规则有所不同,比如 Date 对象会先调用 toString 。其他对象都是默认先转 Number。
JS引擎内部转换为原始值ToPrimitive(obj,preferredType)函数接受两个参数,第一个obj为被转换的对象,第二个preferredType为希望转换成的类型(默认为空,接受的值为Number或String) 在执行ToPrimitive(obj,preferredType)时如果第二个参数为空并且obj为Date的实例时,此时preferredType会被设置为String,其他情况下preferredType都会被设置为Number。
参考:https://www.zhihu.com/question/21484710
let o ={
valueOf(){
return 1
},
toString(){
return 2
},
[Symbol.toPrimitive](){
return 3
}
}
console.log(o+4) // 7
布尔类型跟其他类型==比较
只要布尔类型参与比较,该布尔类型的值首先会被转换为数字类型
根据布尔类型的ToNumber规则,true转为 1,false转为 0
false == 0 // true
true == 1 // true
true == 2 // false 注意这个
数字类型 和 字符串类型的相等比较
当数字类型 和 字符串类型做相等比较时,字符串类型会被转换为数字类型
根据字符串的ToNumber规则,如果是纯数字形式的字符串,则转为对应的数字,空字符转为0, 否则一律按转换失败处理,转为NaN
0 == '' // true
1 == '1' // true
1e21 == '1e21' // true
Infinity == 'Infinity' // true
true == '1' // true
false == '0' // true
false == '' // true
对象类型 和 原始类型的相等比较
- 当对象类型 和 原始类型做相等比较时,对象类型会依照 ToPrimitive 规则转换为原始类型
// 这里其实是先 {} 调用 valueOf 方法返回 {},因不是原始类型,
// 继续调用 toString,返回 '[object Object]' 。所以才会相等
'[object Object]' == {} // true
'1,2,3' == [1, 2, 3] // true
[2] == 2 // true 注意这个
总结:布尔类型、字符串进行 == 运算都会先将布尔类型、字符串转为数字类型再比较。对象则会先转为原始类型再比较。
null 、undefined
null、undefined 两个是 == 的,跟其他的都不 ==。
null == undefined // true
null == 0 // false
undefined == 0 // false
null == '' // false
undefined == '' // false
1、解释下面的这道题,为什么返回true呢???
[] == ![] // true
1、首先右边的 ! 取反会先运算,得到 false,Boolean 比较先转换为数字 Number( false ) 得到 0;
2、左边的[]会先转成基本数据类型,再转数字进行比较。实际的执行过程: Number([]) => Number(‘’) => Number(0) => 0
3 0 == 0 所以返回 true
2、实现 a==1 && a==2 && a==3
const a = {
num: 0,
valueOf: function() {
return this.num += 1
}
};
const equality = (a==1 && a==2 && a==3);
console.log(equality); // true
3、
var o = {}
console.log( o + '' )
console.log( {} + '' )
o + ''
{} + ''
上面的两个的输出是什么呢?
答案是: 前三个都会输出 “[object Object]” ,因为对象进行字符串计算会先调用 toString 方法,最后一个 {} + ‘’,前面的 {} 会被编译成一个块级作用域,而不是理解的对象。所以 {} + ‘’ => +’ ‘ => 0
**
关于 + 运算符
规则:
- 只要有一个是 string ,则另一个值也转为 string,再相加。
- 否则都转为 number,在相加,如果转为 number 有 NaN ,则结果也是 NaN.
true + 1 // 1,布尔型转化为了数字
// 空数组转化为了字符串:数组先调用 valueOf() 方法,返回的是 [],继续调用 toString 方法,才返回 ''
[] + 1 // '1'
{} + 1 // 1,空对象被当成了空代码块,相当于 + 1
var now = new Date()
typeof (now + 1) // 'string',日期对象转化为了字符串
1 + undefined // NaN
1 + {} // '1[ojbect Object]'
true + true // 2
true + {} // 'true[object Object]'
+'' // 0
JS中进行 A+B 这种操作时会经历这样一个过程:
- 将A和B都转换为原始值(primitive,执行ToPrimitive),这里记为A1,B1
- 如果A1和B1中有一个值为string,则将A1、B1都转换为 string(执行ToString),其值记为A2、B2,将A2 B2连接后就是A+B的结果
- 否则的话将A1、B1都转换为 number(执行ToNumber),其值记为A3、B3,将A3 B3相加即为A+B的结果
ToPrimitive(obj,preferredType)
**
JS引擎内部转换为原始值ToPrimitive(obj,preferredType)函数接受两个参数,第一个obj为被转换的对象,第二个preferredType为希望转换成的类型(默认为空,接受的值为Number或String)
在执行ToPrimitive(obj,preferredType)时如果第二个参数为空并且obj为Date的实例时,此时preferredType会被设置为String,其他情况下preferredType都会被设置为Number。
如果preferredType为Number,ToPrimitive执行过程如下:
- 如果obj为原始值,直接返回;
- 否则调用 obj.valueOf(),如果执行结果是原始值,返回之;
- 否则调用obj.toString(),如果执行结果是原始值,返回之;
- 否则抛异常。
如果preferredType为String,将上面的第2步和第3步调换,即:
- 如果obj为原始值,直接返回;
- 否则调用obj.toString(),如果执行结果是原始值,返回之;
- 否则调用 obj.valueOf(),如果执行结果是原始值,返回之;
- 否则抛异常。
**
从 []==![] 为 true 来剖析 JavaScript 各种蛋疼的类型转换:https://github.com/jawil/blog/issues/1
一道面试题引发的对 javascript 类型转换的思考:https://www.cnblogs.com/coco1s/p/6509141.html
从一道面试题说起—js隐式转换踩坑合集:https://juejin.im/post/5bc5c752f265da0a9a399a62