前言
使用过vue开发的盆友都知道Vue2和Vue3的响应式原理是不一样的,vue2用的是Object.defineProperty,vue3用的是proxy。那他们具体是什么呢?又有什么区别呢?下面叫我简单做个笔记。有什么错误望各位大佬不吝指点。
什么是Object.defineProperty()
Object.defineProperty是 es5 引入的一个方法,用于定义或修改对象的属性的方法,可以控制属性的特性(如可枚举性、可配置性、可写性等)。
Object.defineProperty()语法
Object.defineProperty(obj, prop, descriptor)
参数说明
- obj:定义属性的对象。
- prop:定义或修改的属性的名称。
- descriptor:属性的描述符对象,包含属性的特性设置。
descriptor 对象下包含的属性
- value:属性的值。
- writable:属性是否可写,即是否可以使用赋值操作符改变属性值。
- configurable:属性描述符是否可以被改变,或者属性是否可以被删除,默认为false。
- enumerable:属性是否可枚举,即是否会出现在使用 for...in 循环时。
- get:一个函数,当属性被读取时调用,返回属性值。
- set:一个函数,当属性被赋值时调用,接收新值作为参数。
<script>
// 定义一个对象名为(person)的对象【对象的属性有(name、sex)】
let person = { name: '小明', sex: '男'}
//给对象(person)添加一个属性名为(age)的属性,属性描述符只包含了 value 属性,表示 age 属性的初始值。
Object.defineProperty(person, 'age', {
value: 18, // 属性的值
enumerable: true, // 属性是否可枚举
writable: true, // 属性是否可写/可修改
configurable: true // 属性是否可以被删除
})
console.log(person);
</script>
proxy简介
Proxy是ES6中的一种用于创建代理对象的特殊对象。它允许我们定义自定义行为,例如拦截和修改对象的默认操作。Proxy可以用于拦截对象的各种操作,包括属性访问、赋值、函数调用等。
Proxy
的构造函数接受两个参数:目标对象(被代理的对象)和一个处理器对象(用于定义拦截器)
常用的拦截方法包括:
get
、set
、apply
、construct、deleteProperty
、has
、getOwnPropertyDescriptor
等。【这些拦截方法会在代理对象进行对应操作时自动触发】
注:Proxy详解见我另一篇文章: ES6之---Proxy简介 这里就不过多叙述了
// 写法:target是目标对象,handler是处理器对象
const proxy = new Proxy(target, handler);
简单示例
let star = {
name: '小明',
age: 18
}
let proxy = new Proxy(star,{
get(targetObj, propoty, receiver) {
console.log(`我是被代理的对象${targetObj}`)
console.log(`我是你访问的被代理的属性${propoty}`)
//receiver是代理对象proxy
return targetObj[propoty]
}
})
vue中defineProperty和proxy对比
1.监听数据的角度
defineproperty
只能监听某个属性而不能监听整个对象。proxy
不用设置具体属性,直接监听整个对象。defineproperty
监听需要知道是哪个对象的哪个属性,而proxy
只需要知道哪个对象就可以了。也就是会省去for in
循环提高了效率。
2.监听对原对象的影响
- 因为
defineproperty
是通过在原对象身上新增或修改属性增加描述符的方式实现的监听效果,一定会修改原数据。- 而
proxy
只是原对象的代理,proxy
会返回一个代理对象不会在原对象上进行改动,对原数据无污染。
3.实现对数组的监听
- 因为数组
length
的特殊性(length 的描述符configurable 和 enumerable 为 false,并且妄图修改 configurable 为 True 的话 js 会直接报错:VM305:1 Uncaught TypeError: Cannot redefine property: length)
defineproperty
无法监听数组长度变化,Vue
只能通过重写数组方法的方式变现达成监听的效果,光重写数组方法还是不能解决修改数组下标时监听的问题,只能再使用自定义的$set
的方式- 而
proxy
因为自身特性,是创建新的代理对象而不是在原数据身上监听属性,对代理对象进行操作时,所有的操作都会被捕捉,包括数组的方法和length
操作,再不需要重写数组方法和自定义set
函数了。(代码示例在下方)
4. 监听的范围
defineproperty
只能监听到value
的get set
变化。proxy
可以监听除[[getOwnPropertyNames]]
以外所有JS
的对象操作。(链接看下方)监听的范围更大更全面。