这一页是"小工具集合":对象这边 Object.is 是个更较真的 ===,Object.assign 是一键把多个对象的属性并到一起;数字这边多了二进制 0b、八进制 0o 的新写法,以及 Number.isNaN、Number.isInteger 这些不偷摸转类型的严格判断。
=== 平时够用,但它对两个特殊情况很"糊涂":它觉得 NaN === NaN 是 false,还觉得 0 === -0 是 true。Object.is 就是来纠正这两点的。
console.log(NaN === NaN); // false(=== 糊涂了) console.log(Object.is(NaN, NaN)); // true ← 较真:NaN 等于 NaN console.log(0 === -0); // true (=== 觉得 ±0 一样) console.log(Object.is(0, -0)); // false ← 较真:0 不等于 -0
如果你平时只是想判断两个值相不相等,用 === 就够了。只有两种场景才需要 Object.is:要判断的可能是 NaN,或者要区分 +0 和 -0。
想象你有一份"默认配置",用户又传了一份"自定义配置",想把后者盖到前者上——Object.assign(目标, 源1, 源2...) 就是干这个的。
let target = { a: 1 }; // 先有个目标对象(默认配置)
// 以前:一个个手动加
target.b = 2; // 手动加 b
target.c = 3; // 手动加 c
// 现在:一次把多个源对象的属性并进目标
Object.assign(target, { b: 2 }, { c: 3 }); // 把后面两个源对象挨个倒进 target
// ^^^^^^ ^^^^^^^^ ^^^^^^^^
// 加到这 来自源1 来自源2
console.log(target); // {a:1, b:2, c:3}
Object.assign(目标, 源1, 源2...) 会把后面所有源对象的属性逐个"并"进目标;同名属性后面的覆盖前面的。做"默认配置 + 用户配置"合并时最常用——用户没传的项用默认,传了的项盖掉默认。
以前写二进制、八进制容易写错,ES6 给了明确的前缀:0b 是二进制,0o 是八进制,0x 是十六进制。
console.log(0b1010); // 10(0b 开头是二进制) console.log(0o17); // 15(0o 开头是八进制) console.log(0x1f); // 31(0x 开头是十六进制)
全局的 isNaN 是个"老好人",会偷偷把传进来的东西先转成数字再判断;Number.isNaN 不转类型,老老实实只认真正的 NaN。
// 全局 isNaN:宽松,先偷偷转类型
console.log(isNaN("abc")); // true("abc" 被转成 NaN 了)
// Number.isNaN:严格,不转类型
console.log(Number.isNaN("abc")); // false("abc" 根本不是 NaN)
console.log(Number.isInteger(3.5)); // false(不是整数)
console.log(Math.trunc(3.9)); // 3(直接砍掉小数部分,不四舍五入)
如果你用全局 isNaN("abc") 判断"这是不是一个 NaN",得到 true 就会被误导——它其实是因为 "abc" 转不成数字才 true 的。判断是不是真 NaN 用 Number.isNaN,判断整数用 Number.isInteger,砍小数用 Math.trunc。
① 可能在什么地方用:合并默认配置与用户配置(Object.assign)、判断两个值是否严格相同(特殊情况用 Object.is)、表单校验是否整数(Number.isInteger)、取整(Math.trunc)。
② 常见的问题:用全局 isNaN 把字符串误判成 NaN;Object.assign 直接改了原对象(目标和源传成同一个);把 Math.trunc 当成四舍五入。
③ 解决思路:要纯判断就用 Number.isNaN;合并时目标传一个空对象 {} 避免污染源;要四舍五入用 Math.round,Math.trunc 只负责砍小数。