详解Vue3的响应式原理解析
程序员文章站
2022-06-17 16:02:39
目录vue2响应式原理回顾vue3响应式原理剖析嵌套对象响应式避免重复代理总结vue2响应式原理回顾// 1.对象响应化:遍历每个key,定义getter、setter// 2.数组响应化:覆盖数组原...
vue2响应式原理回顾
// 1.对象响应化:遍历每个key,定义getter、setter // 2.数组响应化:覆盖数组原型方法,额外增加通知逻辑 const originalproto = array.prototype const arrayproto = object.create(originalproto) ;['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort'].foreach( method => { arrayproto[method] = function () { originalproto[method].apply(this, arguments) notifyupdate() } } ) function observe (obj) { if (typeof obj !== 'object' || obj == null) { return } // 增加数组类型判断,若是数组则覆盖其原型 if (array.isarray(obj)) { object.setprototypeof(obj, arrayproto) } else { const keys = object.keys(obj) for (let i = 0; i < keys.length; i++) { const key = keys[i] definereactive(obj, key, obj[key]) } } } function definereactive (obj, key, val) { observe(val) // 解决嵌套对象问题 object.defineproperty(obj, key, { get () { return val }, set (newval) { if (newval !== val) { observe(newval) // 新值是对象的情况 val = newval notifyupdate() } } }) } function notifyupdate () { console.log('页面更新!') }
vue2响应式弊端:
响应化过程需要递归遍历,消耗较大
新加或删除属性无法监听
数组响应化需要额外实现
map、set、class等无法响应式
修改语法有限制
vue3响应式原理剖析
vue3使用es6的proxy特性来解决这些问题。
function reactive (obj) { if (typeof obj !== 'object' && obj != null) { return obj } // proxy相当于在对象外层加拦截 // http://es6.ruanyifeng.com/#docs/proxy const observed = new proxy(obj, { get (target, key, receiver) { // reflect用于执行对象默认操作,更规范、更友好 // proxy和object的方法reflect都有对应 // http://es6.ruanyifeng.com/#docs/reflect const res = reflect.get(target, key, receiver) console.log(`获取${key}:${res}`) return res }, set (target, key, value, receiver) { const res = reflect.set(target, key, value, receiver) console.log(`设置${key}:${value}`) return res }, deleteproperty (target, key) { const res = reflect.deleteproperty(target, key) console.log(`删除${key}:${res}`) return res } }) return observed } //代码测试 const state = reactive({ foo: 'foo', bar: { a: 1 } }) // 1.获取 state.foo // ok // 2.设置已存在属性 state.foo = 'fooooooo' // ok // 3.设置不存在属性 state.dong = 'dong' // ok // 4.删除属性 delete state.dong // ok
嵌套对象响应式
测试:嵌套对象不能响应
// 设置嵌套对象属性 react.bar.a = 10 // no ok
添加对象类型递归
// 提取帮助方法 const isobject = val => val !== null && typeof val === 'object' function reactive (obj) { //判断是否对象 if (!isobject(obj)) { return obj } const observed = new proxy(obj, { get (target, key, receiver) { // ... // 如果是对象需要递归 return isobject(res) ? reactive(res) : res }, //... }
避免重复代理
重复代理,比如
reactive(data) // 已代理过的纯对象
reactive(react) // 代理对象
解决方式:将之前代理结果缓存,get时直接使用
const toproxy = new weakmap() // 形如obj:observed const toraw = new weakmap() // 形如observed:obj function reactive (obj) { //... // 查找缓存,避免重复代理 if (toproxy.has(obj)) { return toproxy.get(obj) } if (toraw.has(obj)) { return obj } const observed = new proxy(...) // 缓存代理结果 toproxy.set(obj, observed) toraw.set(observed, obj) return observed } // 测试效果 console.log(reactive(data) === state) console.log(reactive(state) === state)
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!
上一篇: Centos8搭建基于kdc加密的nfs
下一篇: 详解Vuex的属性和作用