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是更好的选择。

相关推荐
wing981 小时前
我的AI编程体验:从白嫖到付费,我为什么最终留下了Codex
前端·人工智能·程序员
京东云开发者2 小时前
京东Taro Native框架静态布局直渲提速
前端
程序员小羊!2 小时前
03JavaScript预备知识
前端
前端的阶梯2 小时前
Cursor 开发 Python 项目完全指南
前端·人工智能·后端
艾伦野鸽ggg2 小时前
JavaScript 基础语法速通
前端·javascript
不懂的浪漫2 小时前
AI 时代还需要买课吗?我用 Skills + Markdown + HTML 搭了一套自学系统
前端·人工智能·html·skill
前端的阶梯2 小时前
Conda 开发 Python 程序完全指南
前端·人工智能·后端
zhengfei6112 小时前
第2章 Agent 核心组件深度解析
前端·javascript·react.js
Linsk2 小时前
前端代码压缩对浏览器兼容性的影响
前端