在读 Winter 大佬的《重学前端》栏目时,重温了 JS 的「拆箱转换」。「装箱转换」与「拆箱转换」之前都是了解的,今天来看,本身所谓的了解也真是只知其一;不知其二。在阅读 Winter 老师写的内容后,对「拆箱转换」这个知识点仍是不甚清楚,所以我再去深刻地了解一番,参考资料详见文末的「参考连接」。javascript
首先,咱们来看一下例子:前端
const a = {
name: 'a',
toString () {
console.log(this);
console.log('toString');
return { name: 'toString' };
},
valueOf () {
console.log(this);
console.log('valueOf');
return { name: 'valueOf' };
}
};
a * 2;
// {name: "a", toString: ƒ, valueOf: ƒ}
// valueOf
// {name: "a", toString: ƒ, valueOf: ƒ}
// toString
// Uncaught TypeError: Cannot convert object to primitive value
a + "";
// {name: "a", toString: ƒ, valueOf: ƒ}
// valueOf
// {name: "a", toString: ƒ, valueOf: ƒ}
// toString
// Uncaught TypeError: Cannot convert object to primitive
alert(a);
// {name: "a", toString: ƒ, valueOf: ƒ}
// toString
// {name: "a", toString: ƒ, valueOf: ƒ}
// valueOf
// Uncaught TypeError: Cannot convert object to primitive value
复制代码
能够看到,toString
和 valueOf
的执行顺序并不固定,而是根据某个条件来决定的,那么是根据什么呢?那就是在拆箱转换时,调用了对象的 ToPrimitive
内部函数时,其会根据执行上下文,自动传入一个转换类型参数,暂时给它命名为 hint
。java
在 JavaScript 标准中,规定了 ToPrimitive
函数,它是对象类型到基本类型转换的实现者(即,拆箱转换);但这是一个内部算法,是编程语言在内部执行时遵循的一套规则。git
对象到 String 和 Number 的转换都遵循“先拆箱再转换”的规则。经过拆箱转换,把对象变成基本类型,再从基本类型转换为对应的 String 或者 Number。github
可是对于不一样的操做,拆箱转换的内部实现也有所区别,正如上面的例子所示。算法
「拆箱转换」的调用规则及顺序以下:编程
[Symbol.toPrimitive]
方法,若是有,直接调用;ToPrimitive
,而后判断传入的 hint
值,若是其值为 string
,顺序调用对象的 toString
和 valueOf
方法(其中 toString
方法必定会执行,若是其返回一个基本类型值,则返回、终止运算,不然继续调用 valueOf
方法);hint
值不为 string
,则就可能为 number
或者 default
了,均会顺序调用对象的 valueOf
和 toString
方法(其中 valueOf
方法必定会执行,若是其返回一个基本类型值,则返回、终止运算,不然继续调用 toString
方法);来看一下第一种状况:微信
const b = {
[Symbol.toPrimitive] (hint) {
console.log(`hint: ${hint}`);
return {};
},
toString () {
console.log('toString');
return 1;
},
valueOf () {
console.log('valueOf');
return 2;
}
};
alert(b); // hint: string
b + ''; // hint: default
b + 500; // hint: default
+b; // hint: number
b * 1; // hint: number
复制代码
第2、三种状况:less
const c = {
toString () {
console.log('toString');
return 1;
},
valueOf () {
console.log('valueOf');
return 2;
}
};
alert(c); // 打印出 toString 并 alert 出 1
c + ''; // 前后打印出 valueOf,"2"
c + 500; // 前后打印出 valueOf,502
+c; // 前后打印出 valueOf,2
c * 1; // 前后打印出 valueOf,2
复制代码
那么关于 hint
可取的三种值,都有什么含义?又什么状况对应什么值?编程语言
hint
取值string
当在但愿是字符串操做,也即发生对象到字符串的转换时,传入内部函数 ToPrimitive 的参数值即为 string
:
// output
alert(obj);
// using object as a property key
anotherObj[obj] = 123;
复制代码
number
当在但愿是数值操做,也即发生对象到数值的转换时,传入内部函数 ToPrimitive 的参数值即为 number
:
// explicit conversion
let num = Number(obj);
// maths (except binary plus)
let n = +obj; // unary plus
let delta = date1 - date2;
// less/greater comparison
let greater = user1 > user2;
复制代码
default
当在一些不肯定须要将对象转换成什么基础类型的场景下,传入内部函数 ToPrimitive 的参数值即为 default
:
// binary plus
let total = car1 + car2;
// obj == string/number/symbol
if (user == 1) { ... };
复制代码
若是亲爱的读者们在本文中发现了什么错误,或者有什么不一样的意见,还请留言,一块儿讨论,一块儿将隐藏的、晦涩的点提出来,而后解决掉。
以为本文不错的话,分享一下给小伙伴吧~