引用类型转换原始类型
有很多转换类型的函数,或者隐式转换,也适用于对象。例如Number()、String()、isNaN()之类,在这个过程中我们不经会好奇,把引用类型变成原始类型中,经历了什么过程?
首先,我们看高程3里面的一句话(结合了一点自己的总结)
isNaN()确实也适用于对象。在基于对象调用isNaN()函数时,调用对象自身的valueOf方法。如果返回原始类型的值,则直接使用该值,不再进行后续步骤。如果valueOf方法返回的还是对象,则改为调用对象自身的toString方法。如果toString方法返回原始类型的值,使用该值,不再进行后续步骤。如果toString方法返回的是对象,就报错。
这个过程也是ECMAScript中内置函数和操作符的一般执行流程
以上加粗的字体就是我们划出的重点:valueOf、toString、一般执行流程。
为了验证以上所说,我们用代码先撸为敬!
// 准备了valueOf和toString两个函数
let obj = {
valueOf() {
console.log('valueOf')
return 1
},
toString() {
console.log('toString')
return '2'
}
};
console.log(isNaN(obj))
运行结果为:
根据以上结果我们能看出是经过了valueOf函数(打印了'valueOf');那么根据上面的引用,我们修改valueOf的返回:
let obj = {
valueOf() {
console.log('valueOf')
return {}
},
toString() {
console.log('toString')
return '2'
}
};
console.log(isNaN(obj))
此时的运行结果为:
这里能看出来,因为首次调用的valueOf返回了引用类型,所以调用toString了函数;最后我们看看,如果toString返回的也是引用类型会是什么结果:
let obj = {
valueOf() {
console.log('valueOf')
return {}
},
toString() {
console.log('toString')
return {} // 也返回了引用类型
}
};
console.log(isNaN(obj))
运行结果:
这时也验证了一开始引用的高程3中所说,会是报错,Cannot convert object to primitive value(无法将对象转换为原始值)
在了解了转换类型的流程之后,我们知道isNaN()函数在接收一个值时,会先尝试将这个值转换成数值,也就是说以上的流程适用于将引用类型转换成数值的方法,例如Number(),那么如果时转换成其他基本类型,例如字符串会是什么结果?
let obj = {
valueOf() {
console.log('valueOf')
return {}
},
toString() {
console.log('toString')
return 'i am obj'
}
};
console.log(String(obj))
运行结果:
能看出直接调用了toString方法;废话不多说,再让toString函数返回引用类型
let obj = {
valueOf() {
console.log('valueOf')
return 'i am obj -- valueOf'
},
toString() {
console.log('toString')
return {}
}
};
console.log(String(obj))
运行结果为:
以上结果等于把转换数值的流程反了过来:先调用toString,如果返回的不是基本类型,再调用valueOf;那么根据这个套路,如果在valueOf函数返回一个引用类型,应该也是会报错,我们看看结果:
let obj = {
valueOf() {
console.log('valueOf')
return {} // 返回引用类型
},
toString() {
console.log('toString')
return {}
}
};
console.log(String(obj))
运行结果:
根据以上测试,我们也能总结出引用类型转换基本类型的流程了,注意,没有返回也是返回了基本类型(undefined)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我们知道,es6新出了一个Symbol的基本类型,其中,在内置的Symbol值中,提到了Symbol.toPrimitive方法,原文链接来自阮一峰的ECMAScript6入门:https://es6.ruanyifeng.com/#docs/symbol#%E5%86%85%E7%BD%AE%E7%9A%84-Symbol-%E5%80%BC,我们先看这个方法的作用
我们试试将这个方法用在以上例子
let obj = {
valueOf() {
console.log('valueOf')
return 1
},
toString() {
console.log('toString')
return '2'
},
[Symbol.toPrimitive]() {
console.log('toPrimitive')
return 3
}
};
console.log(String(obj))
运行结果:
能看出来,首先直奔toPrimitive方法(转为原始类型就调用次方法,不管是字符串还是数值及其他);我们想,既然valueOf或者toString返回了引用类型的话,还是有余地去调用对应的方法,如果还是返回引用类型才会报错,那我们在toPrimitive返回是引用类型又会怎么样?
let obj = {
valueOf() {
console.log('valueOf')
return 1
},
toString() {
console.log('toString')
return '2'
},
[Symbol.toPrimitive]() {
console.log('toPrimitive')
return {}
}
};
console.log(String(obj))
结果是直接报错;
综合刚刚的转换流程及内置方法,得出最后的结论
上一篇: PHP引号前添加反斜杠、去除反斜杠的方法
下一篇: 高性能php日志系统解析