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

相关推荐
Dontla4 分钟前
Canonical URL介绍(规范网址 / 规范链接)(Canonical Tag 规范标签)HTML标签、SEO优化
前端·html·seo
晓得迷路了8 分钟前
栗子前端技术周刊第 138 期 - NestJS 12、Astro 7.1、npm 12...
前端·javascript·nestjs
学习-学习20 分钟前
前端打包后白屏不报错:从 source-map、MIME、路由 base 到 chunk 加载失败的全链路排查
前端
三84432 分钟前
笔记:在同一个物理服务器上通过nginx的虚拟主机生成多个不同的web站点
java·前端·nginx
double_eggm34 分钟前
uniapp.3
开发语言·前端·javascript
索西引擎1 小时前
【React】状态提升模式:设计原理、权衡分析与架构决策框架
前端·react.js·架构
胡萝卜术9 小时前
力扣5. 最长回文子串
前端·javascript·面试
我星期八休息9 小时前
网络编程—应用层HTTP协议
linux·运维·开发语言·前端·网络·网络协议·http
不好听61310 小时前
前端路由完全指南(下篇):懒加载、History 栈与工程化实践
前端·react.js
圣光SG12 小时前
Java Web入门基础知识笔记
java·前端·笔记