最近又遇到空值匹配的问题, 在编写javascript代码时, 尤其是需要和后端同学配合的时候, 空值处理不好是非常容易出问题的, 趁此机会彻底搞清楚吧.
1. 准备工作: 使用脚本生成各种边界值的 == 和 ===比较结果, 这份结果基本涵盖了js中能遇到的所有常见或常用的数据类型和结构.
2. 比较结果:
| == | 0 | 1 | -0 | NaN | "" | foo | {} | { f: "b" } | [] | ["foo"] | true | false | null | undefined | Infinity | -Infinity |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | true | |||||||||||||||
| 1 | false | true | ||||||||||||||
| -0 | true | false | true | |||||||||||||
| NaN | false | false | false | false | ||||||||||||
| "" | true | false | true | false | true | |||||||||||
| foo | false | false | false | false | false | true | ||||||||||
| {} | false | false | false | false | false | false | true | |||||||||
| { f: "b" } | false | false | false | false | false | false | false | true | ||||||||
| [] | true | false | true | false | true | false | false | false | true | |||||||
| ["foo"] | false | false | false | false | false | true | false | false | false | true | ||||||
| true | false | true | false | false | false | false | false | false | false | false | true | |||||
| false | true | false | true | false | true | false | false | false | true | false | false | true | ||||
| null | false | false | false | false | false | false | false | false | false | false | false | false | true | |||
| undefined | false | false | false | false | false | false | false | false | false | false | false | false | true | true | ||
| Infinity | false | false | false | false | false | false | false | false | false | false | false | false | false | false | true | |
| -Infinity | false | false | false | false | false | false | false | false | false | false | false | false | false | false | false | true |
| === | 0 | 1 | -0 | NaN | "" | foo | {} | { f: "b" } | [] | ["foo"] | true | false | null | undefined | Infinity | -Infinity |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | true | |||||||||||||||
| 1 | false | true | ||||||||||||||
| -0 | true | false | true | |||||||||||||
| NaN | false | false | false | false | ||||||||||||
| "" | false | false | false | false | true | |||||||||||
| foo | false | false | false | false | false | true | ||||||||||
| {} | false | false | false | false | false | false | true | |||||||||
| { f: "b" } | false | false | false | false | false | false | false | true | ||||||||
| [] | false | false | false | false | false | false | false | false | true | |||||||
| ["foo"] | false | false | false | false | false | false | false | false | false | true | ||||||
| true | false | false | false | false | false | false | false | false | false | false | true | |||||
| false | false | false | false | false | false | false | false | false | false | false | false | true | ||||
| null | false | false | false | false | false | false | false | false | false | false | false | false | true | |||
| undefined | false | false | false | false | false | false | false | false | false | false | false | false | false | true | ||
| Infinity | false | false | false | false | false | false | false | false | false | false | false | false | false | false | true | |
| -Infinity | false | false | false | false | false | false | false | false | false | false | false | false | false | false | false | true |
3. 不同之处

我把 === 的比较结果中与==不同的部分, 使用红色方框标出.
4. 结论
- 在两张表的对角线上都是自己与自己比较, 除
NaN这朵奇葩之外, 其他所有值都与自身相等. 这是因为IEEE 754 就是这么规定的. -
0,+0,-0等价, (使用Object.is可以区分); -
Infinity-Infinity都只和自身相等===, 和其他任何类型任何值都不等; - 不同部分(红色框内容)都是
===的结果是false而==结果是true, 这是因为==操作包含隐式转换,===操作则不包含, 隐式转换是指:
相等操作符比较两个值是否相等,在比较前将两个被比较的值转换为相同类型。在转换后(等式的一边或两边都可能被转换),最终的比较方式等同于全等操作符 === 的比较方式。 相等操作符满足交换律。
转换规则:
undefined和null互相相等, 但是与其他四种类型(Number,String,Boolean,Object)不等;
Number与其他类型比较时, 其他类型ToNumber|ToPrimitive;
Object与其他类型比较时, 自身ToPrimitive;
String与Boolean比较时, 双方ToNumber;
-
[]空数组, 会被隐式转换为false或者0, 而空对象不会; -
Object类型互相比较时, 两种方式都是比较内存引用是否同一引用对象, 而不是比较其属性值或者ToPrimitive, 示例中相等是因为引用的同一对象. -
javascript中还有"同值相等", "零值相等",Object.is的比较方法, 具体可参考文末链接.
5. 建议
1 编写与 RESTful API 交互应用时应与编写 API 的同学约定好数据交换协议, 比如属性为空时如何体现:
// 任然返回该属性, 以null || ''表示
{
name: 'Jack',
hobbies: null,
alias: ''
}
// 不包含该属性
{
name: 'Jack'
}
两种方式各有优劣, 只是后续处理时略有不同, 如果事先没有考虑这方面的情况, 那么未知情况可能随时发生, 页面上有可能会出现 undefined 或者 null 之类的文字.
2 数组处理尤为重要, 同上一条, 为空时的数组究竟是不返回, 还是返回null, 或者返回空数组 []? 每个人都有自己的看法, 但是前端同学需要自己处理好各种情况的返回 避免被坑.
参考:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators