加载笔记内容...
加载笔记内容...
Math对象作为JavaScript内置的数学工具库,其方法实现直接依赖于底层硬件架构和IEEE 754标准。这里有几个关键点需要特别注意:
1console.log(0.1 + 0.2 === 0.3); // false
这是由于二进制浮点数无法精确表示十进制小数导致。解决方案:
1const floatEqual = (a, b) => Math.abs(a - b) < Number.EPSILON;
随机数生成原理:
Math.random()
使用伪随机算法(Xorshift128+),其周期为2^128-1。在安全敏感场景应使用crypto.getRandomValues()
舍入方法的差异:
Math.floor(-2.5)
=> -3Math.trunc(-2.5)
=> -2Math.round(-2.5)
=> -2 (遵循四舍六入五取偶规则)React等现代框架强烈推荐不可变数据模式,避免直接修改原数组:
1// 错误示范
2const newArr = arr.sort(); // 改变原数组
3
4// 正确做法
5const newArr = [...arr].sort();
includes()
比indexOf()
更语义化,但两者时间复杂度均为O(n)for...of
比forEach()
有更好的性能(Chrome V8中快约20%)V8引擎的sort()方法采用混合排序策略:
自定义比较函数时需注意:
1// 正确数值排序
2arr.sort((a, b) => a - b);
3
4// 对象数组排序
5users.sort((a, b) => a.age - b.age || a.name.localeCompare(b.name));
flat(Infinity)
在处理深层嵌套数组时可能引发栈溢出。安全实现:
1function deepFlatten(arr) {
2 const stack = [...arr];
3 const res = [];
4 while (stack.length) {
5 const next = stack.pop();
6 Array.isArray(next) ? stack.push(...next) : res.push(next);
7 }
8 return res.reverse();
9}
特性 | Map | Object |
---|---|---|
键类型 | 任意类型 | String/Symbol |
元素顺序 | 插入顺序 | 数字升序+插入顺序 |
原型污染 | 无 | 可能 |
序列化 | 需自定义 | 原生支持JSON |
内存回收 | 弱引用支持 | 强引用 |
性能(百万次操作) | 添加:350ms | 添加:500ms |
查询:200ms | 查询:250ms |
1const domData = new WeakMap();
2function storeData(element, data) {
3 domData.set(element, data);
4}
1class LRUCache {
2 constructor(capacity) {
3 this.cache = new Map();
4 this.capacity = capacity;
5 }
6
7 get(key) {
8 if (!this.cache.has(key)) return -1;
9 const value = this.cache.get(key);
10 this.cache.delete(key);
11 this.cache.set(key, value);
12 return value;
13 }
14}
1const obj = {};
2Object.defineProperty(obj, 'readOnlyProp', {
3 value: 42,
4 writable: false,
5 enumerable: true,
6 configurable: false
7});
8
9// 尝试修改会静默失败(严格模式报错)
10obj.readOnlyProp = 100;
避免使用__proto__
,改用:
1const safeObj = Object.create(null); // 无原型链的纯净对象
可变方法 | 不可变替代方案 |
---|---|
push | [...arr, newItem] |
pop | arr.slice(0, -1) |
shift | arr.slice(1) |
unshift | [newItem, ...arr] |
sort | [...arr].sort() |
reverse | [...arr].reverse() |
splice | [...arr.slice(0, start), ...newItems, ...arr.slice(end)] |
1// 使用for循环代替数组方法
2function sum(arr) {
3 let total = 0;
4 for (let i = 0; i < arr.length; i++) {
5 total += arr[i];
6 }
7 return total;
8}
自定义可迭代对象:
1const range = {
2 *[Symbol.iterator]() {
3 for (let i = 0; i < 5; i++) {
4 yield i;
5 }
6 }
7};
8
9console.log([...range]); // [0, 1, 2, 3, 4]
1let domNode = document.createElement('div');
2const map = new Map();
3map.set(domNode, 'data');
4
5// 即使移除DOM节点,Map仍保持引用导致内存泄漏
6domNode = null;
7
8// 使用WeakMap自动回收
9const weakMap = new WeakMap();
10weakMap.set(domNode, 'data'); // 当domNode被GC回收时,条目自动删除
1const arr = [1, 2, 3];
2arr.at(-1); // 3
1const inventory = [
2 { name: 'asparagus', type: 'vegetables' },
3 { name: 'banana', type: 'fruit' }
4];
5
6Object.groupBy(inventory, ({ type }) => type);
1const record = #{ x: 1, y: 2 };
2const tuple = #[1, 2, 3];
1console.table([{a:1, b:2}, {a:3, b:4}]);
2
3// 性能测量
4console.time('filter');
5arr.filter(x => x > 0);
6console.timeEnd('filter');
console.memory
查看堆使用情况map/filter/reduce
组合1function safeAccess(arr, index) {
2 if (!Array.isArray(arr)) throw new TypeError();
3 return index >= 0 ? arr[index] : arr[arr.length + index];
4}
通过深入理解JavaScript核心机制,开发者可以写出更高效、更健壮的代码。随着ECMAScript标准的不断演进,保持对新特性的关注和学习,是每个前端工程师的必修课。