在理解隐式转换前,需要先提到两个概念:
- 装箱转换:正是把基本类型转换为对应的对象,它是类型转换中一种相当重要的种类。每一种基本类型 Number、String、Boolean、Symbol 在对象中都有对应的类。
- 拆箱转换:在 JavaScript 标准中,规定了 ToPrimitive 函数,它是对象类型到基本类型的转换。
装箱转换
装箱转换的3种方式
- new的形式
- 使用call方法
- 使用Object函数
var symObj = (function(){return this;}).call(Symbol("a"));
var symObj = Object(Symbol("a"))
console.log(typeof symObj); //object
console.log(symObj instanceof Symbol); //true
console.log(symObj.constructor == Symbol); //true
- 如何准确识别对象的基本类型? 每一类装箱对象皆有私有的 Class 属性,这些属性可以用 Object.prototype.toString 获取:
console.log(Object.prototype.toString.call(symObj)); //[object Symbol]
在 JavaScript 中,没有任何方法可以更改私有的 Class 属性,因Object.prototype.toString 是可以准确识别对象对应的基本类型的方法,它比 instanceof 更加准确。但需要注意的是,call 本身会产生装箱操作,所以需要配合 typeof 来区分基本类型还是对象类型。
拆箱转换
-
拆箱转换会尝试调用 valueOf 和 toString 来获得拆箱后的基本类型。如果 valueOf 和 toString 都不存在,或者没有返回基本类型,则会产生类型错误 TypeError。
-
如何理解隐式转换(拆箱转换)的 valueOf,toString调用顺序
let ss = "";
let ssObj= (function () {
return this;
}).call(ss);
console.log(typeof ssObj); // object
console.log(ssObj instanceof String); // true
console.log(ssObj.constructor === String); // true
// 可以看出 ssObj 是String装箱后的对象
ssObj.valueOf = () => {console.log("valueOf"); return {}};
ssObj.toString = () => {console.log("toString"); return {}};
ssObj + ss;
// valueOf
// toString
// Uncaught TypeError
// 由此可见,操作符号“+” 的 toPrimitive的默认是Numer,与原数据类型无关
- 到 String 的拆箱转换会优先调用 toString。我们把刚才的运算从 ssObj + ss 换成 String(ssObj),那么你会看到调用顺序就变了。
console.log(String(ssObj))
// toString
// valueOf
// Uncaught TypeError
- 在 ES6 之后,还允许对象通过显式指定 @@toPrimitive Symbol 来覆盖原有的行为。
ssObj[Symbol.toPrimitive] =
() => {
console.log("toPrimitive");
return "hello";
}
console.log(ssObj + "")
// toPrimitive
// hello
其他注意
- js“类型”中,typeof 的运算结果,与运行时类型的规定不一致的地方:
参考文献
- 此文章为3月Day1学习笔记,内容来源于极客时间《重学前端》
最后
文中若有我没说清楚或错误的地方
欢迎v我yxdiet,备注下是掘金的小伙伴!
反手赞一个叭!对我是莫大的鼓励 💗