02-vue源码分析之 vue3.0为何弃用Object.defineProperty而选择Proxy

简介: 02-vue源码分析之 vue3.0为何弃用Object.defineProperty而选择Proxy

前言


在3.0中 双向绑定将会使用Proxy来代替2.x版本的Object.defineProperty,那么我们来看一下Proxy对比defineProperty优势在哪

首先这两种都是基于数据劫持实现的双向绑定


什么是数据劫持


当访问或者设置对象的属性的时候,触发相应的函数,并且返回或者设置属性的值。vue通过Object.defineProperty来劫持对象属性的getter和setter操作,当数据发生变化时发出通知。

const data= {
    name: '若城',
    sex: '男'
}
// 遍历对象,对其属性值进行劫持
Object.keys(data).forEach(key => {
  let val = data[key]
  Object.defineProperty(data, key, {
    enumerable: true, // 该属性可被枚举
    configurable: true, // 该属性可以被删除以及属性描述符可以被改变
    get () {
      console.log(`属性值${data}当前值为${val}`)
      return val
    },
    set (newValue) {
      console.log(`监听到属性值${data}由${val}变为${newValue}`)
      val = newValue
    }
  })
});
data.name // 属性值name当前值为若城
data.name = '新—》若城' // 监听到属性值name由若城变为新—》若城
data.sex // 属性值sex当前值为男

数据劫持的优势


1.不需要进行显示调用,vue的双向绑定原理就是通过数据劫持+发布订阅来实现的,比如angular的脏检查需要通过显示调用markForCheck,react则需要通过setState来进行显示调用

2.通过属性的劫持可以精准获得变化的内容,这部分不需要额外的diff操作,减少性能消耗


vue实现双向绑定


1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。这里需要注意,递归的时候由于属性的值可能也是一个对象,在递归处理对象属性值的时候 ,递归循环引用对象很容易出现递归爆栈问题,在vue中已经通过定义Observer对象记录已经被设置过setter和getter方法的对象,避免了此问题,但如果需要扩展对象,必须手动给新属性设置setter和getter方法,这就是为什么不在data中预先声明好的属性无法进行双向绑定,需要通过this.$set()来设置

this.$set(this.data.key, value) !注意,这是1.0的写法

this.$set(this.data,”key”,value) !这个是2.0的写法

2.实现一个订阅者Watcher,作为连接Observer和Compile的桥梁,可以收到属性的变化通知并执行相应的函数,从而更新视图。

3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。


Object.defineProperty缺陷


1.性能:如果通过遍历对象的属性进行监听,但是属性值也是对象就需要深度遍历了,这时候显然能够劫持完整对象更好

2.无法监听数组:如果属性值是数组,数组也算是一种特殊的对象,下标其实就是对象的属性,理论上是可以通过Object.defineProperty来处理的,那尤大大为什么没有采用这种方式呢,猜测源于数组的使用场景,数组的主要操作场景是遍历,如果每一个元素都挂载set和get方法,会产生巨大性能消耗,而且数组下标变化频繁,操作方法居多,一旦数组长度发生变化,在无法自动检测的状态下,手动更新会是一个相当繁琐的工作

那vue中是如何实现对数组的劫持呢,肯定不能直接篡改Array.prototype 对象,因为会影响所有的数组实例,尤大大通过原型继承得到一个新的原型对象,在此基础上,劫持了7种常用的数组操作进行了重写,分别是push() 、pop() 、shift()、 unshift() 、splice() 、sort()、 reverse(),Vue.set()对于数组的处理其实就是调用了splice方法


Proxy的优势


Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”,即对编程语言进行编程。Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写,可以这样认为,Proxy是Object.defineProperty的全方位加强版

阮一峰Proxy 详解

相关文章
|
2月前
|
JavaScript
vue学习(7)Object.defineProperty
vue学习(7)Object.defineProperty
38 2
|
1月前
|
JavaScript
Vue 的响应式原理中 Object.defineProperty 有什么缺陷
Vue 的响应式原理主要依赖于 `Object.defineProperty`,但该方法存在一些缺陷:无法检测到对象属性的添加和删除,且对大量数据进行代理时性能较差。Vue 3 中改用了 Proxy 来解决这些问题。
|
1月前
|
JavaScript 前端开发 UED
为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty
Vue 3.0 采用 Proxy 替代 Object.defineProperty,主要因为 Proxy 提供了更全面、高效的数据拦截能力,支持对更多操作进行拦截和自定义处理,同时减少了对对象的限制,提升了框架性能和开发体验。
|
3月前
|
JavaScript 前端开发 开发者
Vue.js 响应式变革来袭!结合热点技术,探索从 Object.defineProperty 到 Proxy 的奇妙之旅,触动你的心
【8月更文挑战第30天】在 Vue.js 中,响应式系统自动追踪并更新数据变化,极大提升了开发体验。早期通过 `Object.defineProperty` 实现,但存在对新旧属性处理及数组操作的局限。Vue 3.0 引入了 `Proxy`,克服了上述限制,提供了更强大的功能和更好的性能。实践中,可根据项目需求选择合适的技术方案,并优化数据操作,利用懒加载等方式提升性能。
43 0
|
6月前
|
JavaScript
Vue报错 Invalid default value for prop “list“: Props with type Object/Array must use a factory
Vue报错 Invalid default value for prop “list“: Props with type Object/Array must use a factory
320 0
|
6月前
|
JavaScript
Vue : Object.defineProperty()
Vue : Object.defineProperty()
46 2
|
JavaScript 前端开发 API
proxy相对于object.defineproperty有哪些优点?
proxy相对于object.defineproperty有哪些优点?
|
6月前
|
缓存 前端开发 JavaScript
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(下)
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(下)
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(下)
|
6月前
|
JavaScript 前端开发 测试技术
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(上)
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(上)
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(上)
|
6月前
|
JavaScript
【Object.defineProperty() | new Proxy()】操作Object
【Object.defineProperty() | new Proxy()】操作Object