隐式转换与判等
算术运算符如何做类型转换?
- 一般规则: 任一操作数不是数字时, 自动对其执行
Number(); - 加号特例:
+中任一操作数是字符串时, 另一方执行String(), 结果为字符串拼接;
1 + "2"; // "12"
1 - "2"; // -1
算术运算的结果规则是什么?
- 两个数字: 返回计算结果, 超出可表示范围时得到
Infinity或-Infinity; - 任一操作数为
NaN: 结果为NaN; - 计算无有效结果 (如负数开平方): 结果为
NaN; - 涉及
Infinity: 乘除0或无逻辑结果时为NaN, 其余情况为Infinity;
关系运算符如何比较不同类型的值?
- 数字对数字: 比较数值大小;
- 字符串对字符串: 逐 code unit 比较, 即比较首个不同字符的编码;
- 数字与字符串: 把字符串转成数字再比较;
- 任一为对象: 先按
valueOf()得到数字, 再退回toString()得到字符串; - 任一为
NaN: 所有关系比较返回false;
== 的转换与判等规则是什么?
- 同类型: 直接按值比较, 对象则比较是否指向同一引用;
null与undefined: 两者宽松相等, 且不与其它值相等;- 数字与字符串: 把字符串转为数字;
- 布尔值: 先转为数字再比较;
- 对象与原始值: 对象按
toPrimitive转为原始值 (先valueOf后toString); - 任一为
NaN:==返回false,!=返回true;
null == undefined; // true
null === undefined; // false
"1" == 1; // true
"1" === 1; // false
NaN == NaN; // false
Symbol.toPrimitive 如何介入隐式转换?
- 重写入口: 对象可定义
Symbol.toPrimitive方法, 接收 hint 并按"number"、"string"、"default"三种提示返回原始值; - 优先级: 定义后优先于
valueOf与toString被调用;
class Bar {
[Symbol.toPrimitive](hint) {
if (hint === "number") return 3;
if (hint === "string") return "string bar";
return "default bar";
}
}
const bar = new Bar();
3 + bar; // "3default bar"
3 - bar; // 0
String(bar); // "string bar"
- 实用推论: 重写
toString/valueOf可以改变判等结果, 这也解释了a == 1 && a == 2 && a == 3这类技巧, 详见 属性描述符与响应式;