Object.defineProperty vs Proxy 对比总结

Object.defineProperty vs Proxy 对比总结

一、基本区别

特性 Object.defineProperty Proxy
出现时间 ES5 (2009) ES6 (2015)
监听范围 单个属性 整个对象
API复杂度 较复杂 更简洁
性能 较好 稍差(但可接受)
浏览器支持 几乎全部 IE不支持

二、核心能力对比

1. 监听范围

javascript 复制代码
// defineProperty - 需要逐个属性定义
const obj = { name: '张三', age: 18 }
Object.defineProperty(obj, 'name', { get() {...}, set() {...} })
Object.defineProperty(obj, 'age', { get() {...}, set() {...} })
// 新增属性无法监听

// Proxy - 监听整个对象
const proxy = new Proxy(obj, {
    get(target, key) {...},
    set(target, key, value) {...}
})
// 所有属性(包括新增)都能监听

2. 数组监听

javascript 复制代码
// defineProperty - 无法直接监听数组变化
const arr = [1, 2, 3]
// 需要重写数组方法才能实现

// Proxy - 完美支持数组
const proxyArr = new Proxy(arr, {
    set(target, key, value) {
        console.log(`设置索引${key}: ${value}`)
        target[key] = value
        return true
    }
})
proxyArr.push(4) // 可以监听到

3. 嵌套监听

javascript 复制代码
// defineProperty - 需要递归遍历
function observe(obj) {
    Object.keys(obj).forEach(key => {
        if (typeof obj[key] === 'object') {
            observe(obj[key]) // 递归
        }
        defineReactive(obj, key)
    })
}

// Proxy - 惰性代理
const proxy = new Proxy(obj, {
    get(target, key) {
        const val = target[key]
        // 只在访问时才代理对象
        if (typeof val === 'object') {
            return new Proxy(val, handler)
        }
        return val
    }
})

三、功能对比

功能 defineProperty Proxy
监听属性读取 ✅ get ✅ get
监听属性赋值 ✅ set ✅ set
监听属性删除 ✅ deleteProperty
监听函数调用 ✅ apply
监听构造函数 ✅ construct
监听in操作符 ✅ has
监听for...in ✅ ownKeys
监听属性定义 ✅ defineProperty

四、实际代码对比

Vue 2 vs Vue 3 响应式

javascript 复制代码
// Vue 2 - defineProperty
function defineReactive(obj, key, val) {
    Object.defineProperty(obj, key, {
        get() {
            console.log(`获取${key}: ${val}`)
            return val
        },
        set(newVal) {
            console.log(`设置${key}: ${newVal}`)
            val = newVal
        }
    })
}

// Vue 3 - Proxy
const reactive = (target) => {
    return new Proxy(target, {
        get(target, key, receiver) {
            const res = Reflect.get(target, key, receiver)
            console.log(`获取${String(key)}`)
            return res
        },
        set(target, key, value, receiver) {
            const res = Reflect.set(target, key, value, receiver)
            console.log(`设置${String(key)}: ${value}`)
            return res
        }
    })
}

五、优缺点总结

Object.defineProperty

优点:

  • 性能较好
  • 兼容性好(IE9+)
  • 可精确控制单个属性

缺点:

  • 无法监听数组变化(需要hack)
  • 无法监听新增/删除属性
  • 需要递归遍历对象
  • API不够直观

Proxy

优点:

  • 监听能力强(13种拦截器)
  • 支持数组、对象新增属性
  • 无需递归(惰性代理)
  • API更简洁
  • 可以代理多种数据结构

缺点:

  • 兼容性稍差(无IE)
  • 性能略低于defineProperty
  • 无法polyfill完全

六、使用场景建议

场景 推荐方案 原因
简单对象监听 defineProperty 性能好,足够用
复杂响应式系统 Proxy 功能强大,维护简单
需要兼容IE defineProperty Proxy不支持IE
数组操作监听 Proxy defineProperty需要hack
动态属性监听 Proxy defineProperty无法监听新增属性
性能敏感场景 defineProperty 执行效率更高

七、最佳实践示例

javascript 复制代码
// 简单属性监听 - 用defineProperty
const formData = {}
Object.defineProperty(formData, 'username', {
    set(val) {
        console.log('输入验证:', val)
        this._username = val
    }
})

// 复杂响应式 - 用Proxy
const reactive = (obj) => {
    return new Proxy(obj, {
        get(target, key) {
            if (typeof target[key] === 'object') {
                return reactive(target[key]) // 递归代理
            }
            return Reflect.get(target, key)
        },
        set(target, key, value) {
            console.log(`更新视图: ${key}=${value}`)
            return Reflect.set(target, key, value)
        }
    })
}

总结

  • defineProperty:简单、性能好、兼容性强,但功能受限
  • Proxy:强大、灵活、语义清晰,但需要现代浏览器

Vue 3 选择 Proxy 是因为它能更好地处理动态属性、数组等复杂场景,代码更简洁。如果不需要兼容IE,Proxy是更好的选择。

相关推荐
BigTopOne1 小时前
【WebRtc】DTLS-SRTP 加密完整流程详解
前端
陈随易1 小时前
pm2 替代品,nodejs&bun 线上部署必备工具
前端·后端·程序员
单线程_012 小时前
从案例分析 Vue3 Tokenizer 源码一
前端·javascript·vue.js
BigTopOne2 小时前
【WebRtc】-ICE Candidate 与 STUN/TURN 原理详解
前端
l1258652 小时前
# LangGraph Memory机制深度解析:短期记忆与长期记忆的工程实践
前端·人工智能·python·langchain·bootstrap
码视野2 小时前
基于 Spring Boot + Vue3 的【大学英语四六级 (CET-4/6) 作文智能评分与句式润色系统】设计与实现(含PRD/三端高保真源码/大屏)
java·前端·人工智能·spring boot·后端·vue3
大模型码小白2 小时前
AI 对话流性能调优:万级消息的虚拟滚动落地
java·大数据·前端·javascript·人工智能·算法·机器学习
xm_xm_xm_13 小时前
react17版本以前类组件常用操作
前端·javascript·react.js
ly76894 小时前
Web 性能优化实战:从 Core Web Vitals 到工程化性能治理
前端·性能优化
冬奇Lab4 小时前
一天一个开源项目(第200篇):next-forge - 生产级 Next.js SaaS 启动模板
前端·前端框架·开源