1. 先说一下vue2
vue2中响应式实现的核心是es5的Object.defineProperty这个api
响应式的具体细节可以查看这篇文章:vue的双向绑定
Object.defineProperty方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。看下它的语法
Object.defineProperty(obj, prop, descriptor)
obj:对象
prop:属性
descriptor:被定义或修改的属性描述对象
在descriptor中,对对象的属性添加getter和setter,用来做数据劫持,在getter和setter中做一些操作实现了响应式
但是这个api也存在一些缺点:
- 因为Object.defineProperty劫持的是对象上的属性,因此实现响应式需要对对象的每个属性进行遍历
- 不能监听对象新增,或者删除属性(无法对新增的属性,直接响应式,如下)
var vm = new Vue({
data:{
a:1
}
})
// vm.b 是非响应的
vm.b = 2
因此又新加了api, Vue.set()和 Vue.delete()来实现新增或者删除时响应式
- 同样,也不能直接通过索引新增数组,也可以通过Vue.set()设置;
另外不能直接修改数组长度length,可以通过数组方法splice实现,因为vue中对数组的7个方法(push,pop,shift,unshift,splice,sort,reverse) 做了处理,实现响应式 - Object.defineProperty 也不能对 es6 新产生的 Map,Set 这些数据结构做出监听
2. vue3的响应式
vue3中通过es6的Proxy代理实现响应式
他的优点在于
- Proxy监听的是整个对象,而不是属性
- 可以监听数组的变化
- 返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改
- Proxy现有13中拦截方法,不仅仅是get,set,如ownKeys、deleteProperty、has 等是 Object.defineProperty 不具备的
- Proxy做为新标准将受到浏览器产商重点持续的性能优化