我们必须认识到 3 与 new Number(3) 是完全不同的值,它们一个是 Number 类型, 一个是对象类型。
Number、String 和 Boolean,三个构造器是两用的,当跟 new 搭配时,它们产生对象,当直接调用时,它们表示强制类型转换。
Symbol 函数比较特殊,直接用 new 调用它会抛出错误,但它仍然是 Symbol 对象的构器。
很多实践中推荐禁止使用“ ==”,而要求程序员进行显式地类型转换后,用 === 比较。
字符串到数字的类型转换:
在不传入第二个参数的情况下,parseInt 只支持 16 进制前缀“0x”,而且会忽略非数字
字符,也不支持科学计数法。在一些古老的浏览器环境中,parseInt 还支持 0 开头的数字作为 8 进制前缀,这是很多错误的来源。所以在任何环境下,都建议传入 parseInt 的第二个参数。
而 parseFloat 则直接把原字符串作为十进制来解析,它不会引入任何的其他进制。
多数情况下,Number 是比 parseInt 和 parseFloat 更好的选择。
装箱转换 :
每一种基本类型 Number、String、Boolean、Symbol 在对象中都有对应的类,所谓装箱转换,正是把基本类型转换为对应的对象,它是类型转换中一种相当重要的种类。
全局的 Symbol 函数无法使用 new 来调用,但我们仍可以利用装箱机制来得到一个 Symbol 对象,我们可以利用一个函数的 call 方法来强迫产生装箱。
//我们定义一个函数,函数里面只有 return this. //然后我们调用函数的 call 方法到一个Symbol 类型的值上. //这样就会产生一个 symbolObject。 var symbolObject = (function(){ return this; }).call(Symbol("a")); console.log(typeof symbolObject); //object console.log(symbolObject instanceof Symbol); //true console.log(symbolObject.constructor == Symbol); //true
装箱机制会频繁产生临时对象,在一些对性能要求较高的场景下,我们应该尽量避免对基本类型做装箱转换。
使用内置的 Object 函数,我们可以在 JavaScript 代码中显式调用装箱能力。
var symbolObject = Object(Symbol("a")); console.log(typeof symbolObject); //object console.log(symbolObject instanceof Symbol); //true console.log(symbolObject.constructor == Symbol); //true
在 JavaScript 中,没有任何方法可以更改私有的 Class 属性,因此
Object.prototype.toString 是可以准确识别对象对应的基本类型的方法,它比 instanceof
更加准确。
但需要注意的是,call 本身会产生装箱操作,所以需要配合 typeof 来区分基本类型还是对
象类型。
拆箱转换:
拆箱转换会尝试调用 valueOf 和 toString 来获得拆箱后的基本类型。如果 valueOf 和
toString 都不存在,或者没有返回基本类型,则会产生类型错误 TypeError。进行 o*2 这个运算的时候,你会看见先执行了 valueOf,接下来是toString,最后抛出了一个 TypeError,这就说明了这个拆箱转换失败了。
var o = { valueOf : () => {console.log("valueOf"); return {}}, toString : () => {console.log("toString"); return {}} } o * 2 // valueOf // toString // TypeError
到 String 的拆箱转换会优先调用 toString。我们把刚才的运算从 o*2 换成 String(o),那
么你会看到调用顺序就变了。var o = { valueOf : () => {console.log("valueOf"); return {}}, toString : () => {console.log("toString"); return {}} } String(o) // toString // valueOf // TypeError
实践问题:
如果我们不用原生的 Number 和 parseInt,用 JS 代码实现String 到 Number 的转换,该怎么做呢?
let StringToNumber = (str)=>{ let arr = str.trim().split('') let sign = arr[0] === '-' ? -1 : 1 //sign标记符号 if (sign === -1 || str[0] === '+') { //如果有符号就删除 arr.shift() } return sign * arr.reduce((total, cur)=>( total * 10 + (cur >= '0' && cur <= '9' ? (cur - '0') : NaN) )) }