1. 首页
  2. Vuejs

尝鲜Vue3之六:响应式原理的革新 – Vue2、Vue3实现对比

目录

响应式是什么

首先我们说说什么是响应式。通过某种方法可以达到数据变了可以自由定义对应的响应就叫响应式。

具体到我们MVVM中 ViewModel的需要就是数据变了需要视图作出响应。 如果用Jest用例便表示就是这样


it('测试数据改变时 是否被响应', () => { const data = reactive({ name: 'abc', age: { n: 5 } }) // Mock一个响应函数 const fn = jest.fn() const result = fn() // 设置响应函数 effect(fn) // 改变数据 data.name = 'efg' // 确认fn生效 expect(fn).toBeCalled() })

假定我们需要的是数据data变化时可以触发fn函数也就是作出相应,当然相应一般是触发视图更新当然也可以不是。我们这里面用jest做了一个Mock函数来检测是否作出相应。

最后代码expect(fn).toBeCalled()有效即代表测试通过也就是作出了相应

Vue2的解决方案

下面展示的是vue2的实现方式是通过Object.defineProperty来重新定义getter,setter方法实现的。


let effective function effect(fun) { effective = fun } function reactive(data) { if (typeof data !== 'object' || data === null) { return data } Object.keys(data).forEach(function (key) { let value = data[key] Object.defineProperty(data, key, { emumerable: false, configurable: true, get: () => { return value }, set: newVal => { if (newVal !== value) { effective() value = newVal } } }) }) return data } module.exports = { effect, reactive }

当然还有两个重要的问题需要处理 第一个就是这样做只能做浅层响应 也就是如果是第二层就不行了。


it('测试多层数据中改变时 是否被响应', () => { const data = reactive({ age: { n: 5 } }) // Mock一个响应函数 const fn = jest.fn() // 设置响应函数 effect(fn) // 改变多层数据 data.age.n = 1 // 确认fn生效 expect(fn).toBeCalled() })

比如以下用例 就过不去了 当然解决的办法是有的 递归调用就好了

尝鲜Vue3之六:响应式原理的革新 - Vue2、Vue3实现对比

当然这样也递归也带来了性能上的极大损失 这个大家先记住。

然后是数组问题 数组问题我们可以通过函数劫持的方式解决


const oldArrayPrototype = Array.prototype const proto = Object.create(oldArrayPrototype); ['push','pop','shift','unshift','splice','sort','reverse'].forEach(method => { // 函数劫持 proto[method] = function(){ effective() oldArrayPrototype[method].call(this,...arguments) } }) // 数组通过数据劫持提供响应式 if(Array.isArray(data)){ data.__proto__ = proto }

Vue3

新版的Vue3使用ES6的Proxy方式来解决这个问题。之前遇到的两个问题就简单的多了。首先Proxy是支持数组的也就是数组是不需要做特别的代码的。对于深层监听也不不必要使用递归的方式解决。当get是判断值为对象时将对象做响应式处理返回就可以了。大家想想这个并不不是发生在初始化的时候而是设置值得时候当然性能上得到很大的提升。


function reactive(data) { if (typeof data !== 'object' || data === null) { return data } const observed = new Proxy(data, { get(target, key, receiver) { // Reflect有返回值不报错 let result = Reflect.get(target, key, receiver) // 多层代理 return typeof result !== 'object' ? result : reactive(result) }, set(target, key, value, receiver) { effective() // proxy + reflect const ret = Reflect.set(target, key, value, receiver) return ret }, deleteProperty(target,key){ const ret = Reflect.deleteProperty(target,key) return ret } }) return observed }

当然目前还是优缺点的缺点,比如兼容性问题目前IE11就不支持Proxy。不过相信ES6的全面支持已经是不可逆转的趋势了,这都不是事。

为了对比理解Vue2、3的响应式实现的不同我把两种实现都写了一下,并且配上了jest测试。大家可以参考一下 github.com/su37josephx…


// clone代码 yarn npx jest reactivity-demo

尝鲜Vue3之六:响应式原理的革新 - Vue2、Vue3实现对比

尝鲜Vue3之六:响应式原理的革新 - Vue2、Vue3实现对比

目录

作者:全栈然叔
链接:https://juejin.im/post/6844903976421310471

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「IT平头哥联盟」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文著作权归作者所有,如若转载,请注明出处

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:尝鲜Vue3之六:响应式原理的革新 – Vue2、Vue3实现对比

链接:https://www.javascriptc.com/4077.html

« nginx入门学习
尤雨溪:Vue3的设计过程»
Flutter 中文教程资源

相关推荐

QR code