LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

尤雨溪搞响应式为什么要从 Object.defineProperty 换成 Proxy

admin
2025年7月25日 14:48 本文热度 164

作者:盏灯

https://juejin.cn/post/7493539513106677769

前言

你说,为什么❓尤雨溪搞响应式,他为什么要换掉Object.defineProperty呢❓

proxy什么来头❓

有一次👀看他直播,说去面试人家问他原型链,他不会,GG了面试黄了,你说他是不是无中生有暗度陈仓凭空想象凭空捏造new Proxy来换掉Object.defineProperty的呢?

还真不是,尤雨溪的响应式,我们暂且叫成插一脚吧👇,请听我细细道来👂

在前端开发中,响应式系统是现代框架的核心特性。无论是 Vue 还是 React,它们都需要实现一个基本功能:当数据变化时,自动更新相关的视图。用通俗的话说,就是要在数据被读取或修改时"插一脚",去执行一些额外的操作(比如界面刷新、计算属性重新计算等)。

// 读取属性时
obj.a; // 需要知道这个属性被读取了

// 修改属性时
obj.a = 3// 需要知道这个属性被修改了

但原生 JavaScript 对象不会告诉我们这些操作的发生。那么,尤雨溪是如何实现这种"插一脚"的能力的呢?

正文

Vue 2 的"插一脚"方案 - Object.defineProperty

基本实现原理

Vue 2 使用的是 ES5 的 `Object.defineProperty`[1] API。这个 API 允许我们定义或修改对象的属性,并为其添加 getter 和 setter。

const obj = { a1 };

let v = obj.a;
Object.defineProperty(obj, 'a', {
get() {
    console.log('读取 a'); // 插一脚:知道属性被读取了
    return v;
  },
set(val) {
    console.log('更新 a'); // 插一脚:知道属性被修改了
    v = val;
  }
});

obj.a;     // 输出"读取 a"
obj.a = 3// 输出"更新 a"

完整对象监听

为了让整个对象可响应,Vue 2 需要遍历对象的所有属性:

function observe(obj{
for (const k in obj) {
    let v = obj[k];
    Object.defineProperty(obj, k, {
      get() {
        console.log('读取', k);
        return v;
      },
      set(val) {
        console.log('更新', k);
        v = val;
      }
    });
  }
}

处理嵌套对象

对于嵌套对象,还需要递归地进行观察:

function _isObject(v{
returntypeof v === 'object' && v !== null;
}

function observe(obj{
for (const k in obj) {
    let v = obj[k];
    if (_isObject(v)) {
      observe(v); // 递归处理嵌套对象
    }
    Object.defineProperty(obj, k, {
      get() {
        console.log('读取', k);
        return v;
      },
      set(val) {
        console.log('更新', k);
        v = val;
      }
    });
  }
}

Vue 2 方案的两大缺陷

缺陷一:效率问题

在这种模式下,他就必须要去遍历这个对象里边的每一个属性...这是第一个缺陷:必须遍历对象的所有属性,对于大型对象或深层嵌套对象,这会带来性能开销。

缺陷二:新增属性问题

无法检测到对象属性的添加或删除:

obj.d = 2// 这个操作不会被监听到

因为一开始遍历的时候没有这个属性,后续添加的属性不会被自动观察。

Vue 3 的"插一脚"方案 - Proxy

基本实现原理

Vue 3 使用 ES6 的 `Proxy`[2] 来重构响应式系统。Proxy 可以拦截整个对象的操作,而不是单个属性。

const obj = { a1 };

const proxy = newProxy(obj, {
get(target, k) {
    console.log('读取', k); // 插一脚
    return target[k];
  },
set(target, k, val) {
    if (target[k] === val) returntrue;
    console.log('更新', k); // 插一脚
    target[k] = val;
    returntrue;
  }
});

proxy.a;     // 输出"读取 a"
proxy.a = 3// 输出"更新 a"
proxy.d;     // 输出"读取 d" - 连不存在的属性也能监听到!

完整实现

function _isObject(v{
returntypeof v === 'object' && v !== null;
}

function reactive(obj{
const proxy = newProxy(obj, {
    get(target, k) {
      console.log('读取', k);
      const v = target[k];
      if (_isObject(v)) {
        return reactive(v); // 惰性递归
      }
      return v;
    },
    set(target, k, val) {
      if (target[k] === val) returntrue;
      console.log('更新', k);
      target[k] = val;
      returntrue;
    }
  });
return proxy;
}

Proxy 的优势

  1. 无需初始化遍历:直接代理整个对象,不需要初始化时遍历所有属性
  2. 全面拦截:可以检测到所有属性的访问和修改,包括新增属性
  3. 性能更好:采用惰性处理,只在属性被访问时才进行响应式处理
  4. 更自然的开发体验:不需要特殊 API 处理数组和新增属性

"proxy 它解决了什么问题?两个问题。

第一个问题不需要深度遍历了,因为它不再监听属性了,而是监听的什么?整个对象。

同时也由于它监听了整个对象,就解决了第二个问题:能监听这个对象的所有操作,包括你去读写一些不存在的属性,都能监听到。"

原理对比与源码解析

原理对比

特性
Object.defineProperty
Proxy
拦截方式
属性级别
对象级别
新增属性检测
不支持
支持
性能
初始化时需要遍历
按需处理
深层嵌套处理
初始化时递归处理
访问时递归处理

源码实现差异

Vue 2 实现

  • 在 src/core/observer 目录下
  • 初始化时递归遍历整个对象
  • 需要特殊处理数组方法

Vue 3 实现

  • 独立的 @vue/reactivity 包
  • 使用 Proxy 实现基础响应式
  • 惰性处理嵌套对象
  • 更简洁的 API 设计

为什么 Proxy 是更好的选择?

  1. 更全面的拦截能力:可以拦截对象的所有操作,包括属性访问、赋值、删除等
  2. 更好的性能:不需要初始化时递归遍历整个对象
  3. 更简洁的 API:不再需要 Vue.set/Vue.delete 等特殊 API
  4. 更自然的开发体验:开发者可以使用普通的 JavaScript 语法操作对象

总结

需显式操作(defineProperty)-> 声明式编程(Proxy)

局部监听(属性级别)-> 全局拦截(对象级别)

从 Object.defineProperty 到 Proxy 的转变,不仅是 API 的升级,更是前端框架设计理念的进步。Vue 3 的响应式系统通过 Proxy 实现了更高效、更全面的数据监听。


该文章在 2025/7/25 14:48:31 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved