← 返回目录

第 13 卷

第 13 / 19 卷日期:

• Proxy的优势场景:

  1. 复杂对象的全生命周期监控:需要拦截属性新增、删除、in运算符等多种操作;
  2. 数组的响应式处理:无需重写数组方法,原生支持数组的索引操作和原型方法拦截;
  3. 面向未来的开发场景:无需兼容IE等旧环境,追求代码简洁性和可维护性。

• Object.defineProperty的优势场景:

  1. 需要兼容IE8及以上的旧环境:如企业级旧系统维护;
  2. 仅需拦截单个/少数属性的读写:无需全面拦截,配置成本低;
  3. 简单的数据校验场景:如对对象的特定属性进行值范围限制,逻辑简单。

(3)总结

Proxy 是ES6对 Object.defineProperty 的功能升级,在拦截范围、使用便捷性、对复杂对象的支持上全面优于后者; Object.defineProperty 的唯一优势是兼容性更好。在现代前端开发中

(无需兼容旧环境), Proxy 已成为数据劫持的首选方案;仅在需要兼容旧环境或简单拦截场景下,才考虑使用 Object.defineProperty。

22. Map和WeakMap又有什么不同?请解释WeakMap的特性,以及为什

么及在什么情况下会选择使用WeakMap而不是Map。

(1)Map和WeakMap的核心区别

Map 和 WeakMap 均是ES6引入的键值对集合类型,核心差异在于键的引用类型、垃圾回收机制、功能支持三个维度,具体对比如下:

对比维度MapWeakMap
键的类型支持任意类型(原始值:字符仅支持引用类型作为键(如对
串、数字、布尔值等;引用类象、数组、函数;原始值作为
型:对象、数组等)键会报错)
键的引用强度强引用:Map会持有键对象的弱引用:WeakMap仅持有键
强引用,即使键对象在外部没对象的弱引用,不影响垃圾回
有其他引用,也不会被垃圾回收。若键对象在外部没有其他
收(GC),导致内存无法释强引用,会被GC自动回收,
放对应的键值对也会从

WeakMap中移除

尺寸获取支持size属性:可直接获不支持size属性:无法直
取键值对的数量接获取键值对数量
功能方法完整:set()、get()、有限:仅支持set()、
has()、delete()、get()、has()、
clear()、迭代方法等delete(),不支持

clear() 和迭代

(2)WeakMap的核心特性

  1. 弱引用键(核心特性):WeakMap的键对对象是弱引用,这意味着键对象的生命周期完全由外部

强引用决定。当外部没有任何强引用指向键对象时,GC会自动回收该键对象,同时WeakMap中对应的键值对也会被自动移除,无需手动清理,避免内存泄漏。

  1. 仅支持引用类型作为键:原始值(如字符串、数字)不能作为WeakMap的键,因为原始值是按值

存储的,不存在引用概念,无法实现弱引用机制。

  1. 无迭代和尺寸获取能力:由于键对象可能被随时回收,WeakMap的键值对数量是动态变化的,因

此不提供迭代器和 size 属性,无法遍历或获取总数量。

  1. 值可以是任意类型:与Map一致,WeakMap的值可以是原始值或引用类型,不受弱引用机制影

响。

(3)选择使用WeakMap而非Map的场景

选择WeakMap的核心原因是避免内存泄漏,适用于“键对象的生命周期与外部强引用绑定”的场景,具体如下:

  1. 对象的私有数据存储:需要为对象关联额外的私有数据,但不希望这些数据影响对象的垃圾回收。

例如,为DOM元素绑定私有状态,当DOM元素被移除(外部无强引用)时,对应的私有数据会自动回收。

  1. 缓存场景(缓存键为引用类型):对引用类型对象进行缓存,当对象不再被使用时,缓存自动失

效,释放内存。例如,缓存函数的计算结果,键为函数的参数对象。

  1. 避免循环引用导致的内存泄漏:当两个对象相互引用时,使用Map会导致二者都无法被GC回收(强

引用);而使用WeakMap存储引用关系,不会阻止GC回收,避免内存泄漏。

  1. 临时关联数据场景:仅需要在对象存在期间关联数据,对象销毁后数据自动清理,无需手动管理数

据生命周期。

(4)总结

  1. 请列举实现异步编程的几种方法,并简要说明它们各自的特点。

JavaScript中实现异步编程的核心目标是避免阻塞主线程,提高程序运行效率。随着语言发展,异步编程方案从简单到复杂、从繁琐到简洁逐步演进,主要有以下5种方法,各有其特点和适用场景:

(1)回调函数(Callback)

最基础的异步编程方案,将异步操作的后续逻辑封装为函数,作为参数传递给异步函数,当异步操作完成后,调用该函数执行后续逻辑。

• 特点:

  1. 实现简单,兼容性好(支持所有ES版本);
  2. 存在“回调地狱”问题:多个异步操作嵌套时,代码缩进层级过深,可读性和可维护性极差;
  3. 错误处理繁琐:多个嵌套回调的错误需要在每个回调中单独处理,容易遗漏;
  4. 无法使用 try/catch 捕获异步错误(早期回调)。

Code block

1

2//示例:回调函数实现异步读取文件(Node.js)
3const fs = require("fs");
4fs.readFile("file1.txt", "utf8", (err, data1) => {
5if (err) throw err;
6fs.readFile("file2.txt", "utf8", (err, data2) => {
7if (err) throw err;
8console.log(data1 + data2);
9});
10});

(2)事件监听(EventEmitter)

基于“发布-订阅”模式,异步操作完成后触发特定事件,通过监听该事件执行后续逻辑。Node.js的 EventEmitter 是典型实现,浏览器中的DOM事件(如 click、 load)也属于此类。

• 特点:

  1. 支持一对多通信:一个事件可被多个监听器监听,适合多模块协作;
  2. 代码解耦:异步操作的触发方与后续逻辑的执行方分离,降低耦合度;
  3. 可能出现“事件丢失”:若监听器注册晚于事件触发,会错过事件;
全站分卷索引 · 19 卷
  1. 1第 1 卷
  2. 2第 2 卷
  3. 3第 3 卷
  4. 4第 4 卷
  5. 5第 5 卷
  6. 6第 6 卷
  7. 7第 7 卷
  8. 8第 8 卷
  9. 9第 9 卷
  10. 10第 10 卷
  11. 11第 11 卷
  12. 12第 12 卷
  13. 13第 13 卷
  14. 14第 14 卷
  15. 15第 15 卷
  16. 16第 16 卷
  17. 17第 17 卷
  18. 18第 18 卷
  19. 19第 19 卷