JavaScript 冷知识合集:这些特性你都知道吗?

hello大家好,我是Range。

JavaScript有很多奇怪的不容易理解的特性(bug?),想要写出比较健壮的JavaScript代码,又不能不去了解这些知识点。今天带来 一篇短文,介绍了一些常见的冷知识。

另外,推荐大家都去看看《Javascript: The Good Parts》这本书,薄薄的一本,也不会耽误刷小视频的时间

下面是正文部分。



JavaScript 冷知识合集:这些特性你都知道吗?

JavaScript 作为一门动态的脚本语言,有着无穷的灵活性和意想不到的特性。即使你已经是一名资深开发者,也可能会对某些冷知识感到意外。本文整理了一些 JavaScript 冷知识,既有实用性,也有趣味性,希望你看完之后可以在项目中实践或者用来和同事“炫技”。


1. [] == ![] 的结果为什么是 true?


console.log([] == ![]); // true
解析:

这个问题乍看起来毫无道理,但实际上是 JavaScript 的类型转换规则导致的。

  1. ![] 转换为布尔值」

    • 空数组是一个对象,它的布尔值为 true,但 ![]false

  2. 「类型转换规则」

    • == 会将两边的操作数转换为相同类型。

    • [] 转为字符串,变成 ""

    • ![]false,转换为数字为 0

  3. 「最终比较」

    • "" == 0true,因为空字符串会被转为数字 0


2. 0.1 + 0.2 === 0.3 为什么是 false?


console.log(0.1 + 0.2 === 0.3); // false
解析:

这是由于 JavaScript 使用 IEEE 754 双精度浮点数表示数字。这种表示方式无法精确存储某些十进制小数,导致计算时产生了微小的误差。


console.log(0.1 + 0.2); // 0.30000000000000004
解决方案:

通过 Number.EPSILON 校正误差:


console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON); // true

3. Object.is() 和 === 的微妙区别


console.log(Object.is(NaN, NaN)); // true
console.log(NaN === NaN); // false
解析:

Object.is() 用来比较两个值是否完全相同,和 === 很相似,但处理特殊值(如 NaN-0)时有区别:

  • NaN 比较」

    • ===NaN 不等于自身。

    • Object.is()NaN 等于自身。

  • -0+0

  • console.log(Object.is(-0, +0)); // false
    console.log(-0 === +0); // true
实用场景:

当你需要精确比较特殊值时,Object.is() 是更可靠的选择。


4. 小数点后直接调用方法

你知道可以直接对数字调用方法吗?不过写法需要小心。


console.log(5..toString()); // "5"
console.log(5 .toString()); // "5"
console.log((5).toString()); // "5"
解析:
  • 第一个点是小数点,第二个点是对象访问符。

  • 为了避免歧义,括号或者额外的空格可以让代码更清晰。


5. JavaScript 的 + 是个多面手

+ 在 JavaScript 中不仅仅是一个加法运算符,它还能用于类型转换:


console.log(+"123"); // 123 (字符串变为数字)
console.log(+true); // 1
console.log(+false); // 0
console.log(+null); // 0
console.log(+undefined);// NaN
实用场景:

快速将字符串转为数字,替代 parseIntNumber()


6. 函数参数的“魔术”变化

JavaScript 的函数参数对象 arguments 并不是一个真正的数组,它是一个“类数组对象”。不过,在严格模式下,它的行为发生了变化。


function test(a, b) {
a = 10;
console.log(arguments[0]); // 非严格模式:10;严格模式:1
}

test(1, 2);
解析:
  • 在非严格模式下,修改参数变量会同步更新 arguments 对象。

  • 在严格模式下,参数和 arguments 之间不再同步。


7. 函数默认参数也有作用域

函数的默认参数值可以访问之前的参数:


function greet(name, message = `Hello, ${name}`) {
return message;
}

console.log(greet("Alice")); // Hello, Alice
解析:

默认参数在定义时会创建作用域链,后面的参数可以引用前面的参数。


8. “冻结”的对象仍可修改内部属性

Object.freeze() 冻结的是对象本身,而非其内部的属性。


const obj = { nested: { value: 1 } };
Object.freeze(obj);

obj.nested.value = 42;
console.log(obj.nested.value); // 42
解决方案:

如果需要真正冻结,可以递归处理:


function deepFreeze(obj) {
Object.freeze(obj);
Object.keys(obj).forEach((key) => {
if (typeof obj[key] === "object") {
deepFreeze(obj[key]);
}
});
}

const obj2 = { nested: { value: 1 } };
deepFreeze(obj2);
obj2.nested.value = 42; // 不会修改

9. setTimeout 的最短延迟时间是 4ms

即使你设置了 setTimeout 的延迟为 0ms,浏览器仍然会将其最短延迟设置为 4ms


setTimeout(() => console.log("Hello"), 0);
console.log("World");
// 输出顺序:World -> Hello
解析:

JavaScript 的事件循环机制规定,setTimeout 的回调最早在下一次事件循环执行,而非立即执行。


10. 使用正则表达式判断素数

虽然看起来不可思议,但你可以用正则表达式判断一个数字是否是素数。


function isPrime(number) {
return !/^1?$|^(11+?)\1+$/.test("1".repeat(number));
}

console.log(isPrime(7)); // true
console.log(isPrime(8)); // false
解析:
  • 正则匹配通过重复检测数字是否可以被整除,若不能整除则为素数。


结语

JavaScript 是一门让人又爱又恨的语言。它的灵活性既给我们带来了便利,也让它充满了奇怪的冷知识。希望这些冷知识能让你在开发中找到新的乐趣!如果你也有发现其他有趣的知识点,欢迎在评论区补充!

原文链接:https://juejin.cn/post/7451763317440790568

最后

还没有使用过我们刷题网站(https://fe.ecool.fun/)或者刷题小程序的同学,如果近期准备或者正在找工作,千万不要错过,题库主打题全和更新快哦~。


有会员购买、辅导咨询的小伙伴,可以通过下面的二维码,联系我们的小助手。