看个题
const a = {};
const b = {};
const obj = {};
obj[a] = 123;
obj[b] = 456;
console.log(obj[a]);
这是一道经典的面试题,其中涉及到了对象键值和类型转换的相关知识点,看完此文你自然会知道此题的答案
对象转boolean,string,number
const obj = {};
console.log(Boolean(obj)); // true
console.log(String(obj)); // [object Object]
console.log(Number(obj)); // NaN
从结果来看,暂时得出以下结论:
- 对象转boolean为true
- 对象转string为[object Object]
- 对象转Number为NaN
那么JS内部究竟是怎样运作的呢
hint
hint是各种情况下类型转换的三种描述
string 描述
对象转字符串,就会匹配到 string hint,如:使用 alert 函数,对象作为键
const obj1 = {};
alert(obj1); // [object Object]
const obj2 = {};
obj2[obj1] = 123; // { '[object Object]': 123 }
number 描述
对象转数字,会匹配到 number hint,通常用于数学运算,一些数学内建函数会包括这种转换,如:+号后转换数字,Date日期对象
const obj = {};
// 一元运算
const a = +obj; // NaN
// 显示转换
const b = Number(obj); // NaN
// date日期对象内建函数
const c = new Date() - new Date(); // 0
// 大于、小于
const d = obj > obj; // false
default 描述
当运算符“不确定”期望值类型的时候会匹配到 default hint,如:二元加法,与字符串、数字、symbol进行==比较时
const obj = {};
// 二元加法
const a = obj + obj; // [object Object][object Object]
// 与number判断
obj == 1 // false
自定义转换方法
为了让用户能自定义某个对象的类型转换,JS提供了三种方法
obj[Symbol.toPrimitive](hint)
Symbol.toPrimitive 是一个是内置的 symbol 属性,指定了 hint 中的三种描述
如果此方法存在,则会被用于所有 hint
let user = {
name: "pangyujs",
value: 666,
[Symbol.toPrimitive](hint) {
console.log("hint=", hint);
if (hint === "string") {
return `My name is ${this.name}`;
} else if (hint === 'number') {
return this.value;
} else {
return "This is a default";
}
},
};
// hint: string
console.log(String(user)) // My name is pangyujs
// hint: number
console.log(+user); // 666
// hint: default(二元表达式用到两次user,隐藏会调用两次)
console.log(user + user); // This is a default
toString()/valueOf()
如果没有 Symbol.toPrimitive,那么 JS 会尝试寻找 toString 和 valueOf
- 对于 string hint:调用
toString,如果不存在,调用valueOf,所以转字符串的时候会优先调用 toString - 对于 number 和 default hint,调用
valueOf,如果不存在,调用toString,所以数学运算时,会优先调用 valueOf
默认情况下,普通对象都有这两个分法,toString 返回 [object Object],valueOf 返回自身
const obj = {};
obj.toString(); // [object Object]
obj.valueOf(); // {}
接下来改写上面 Symbol.toPrimitive 提出的例子
let user = {
name: "pangyujs",
value: 666,
toString() {
return `My name is ${this.name}`;
},
valueOf() {
return this.value;
},
};
// hint: string
console.log(String(user)) // My name is pangyujs
// hint: number
console.log(+user); // 666
// hint: default(二元表达式用到两次user,隐藏会调用两次)
console.log(user + user); // 1332
可以说明 string hint 会优先调用 toString,number、default hint 会优先调用 valueOf
注意:如果没有 Symbol.toPrimitive 和 valueOf, toString 将处理所有类型转换
做题
const a = {};
const b = {};
const obj = {};
obj[a] = 123;
obj[b] = 456;
console.log(obj[a]);
在对象作为键的时候,会默认走 string hint,所以 a 和 b 都会转为 [object Object] 字符串,最后 b 的赋值覆盖了 a,答案为 456
控制台打印结果:
总结
对象类型转换,是由内建函数和运算符自动调用的,有三种类型描述
- string:对于 alert 和其他需要字符串的操作
- number:对于数学运算
- default:少数运算符,通常和 number 相同的方式转换
实际使用中,通常只实现 toString 就满足大部分需求了,像 Array,Number 等都重写了 toString 方法