初识VUE响应式原理
作者:京东零售 吴静
自从Vue发布以来,就受到了广大开发人员的青睐,提到Vue,我们首先想到的就是Vue的响应式系统,那响应式系统到底是怎么回事呢?接下来我就给大家简单介绍一下Vue中的响应式原理。
vue2的响应式原理
尽管Vue2将于2023年12月31日停止维护,但是我们依然有很多项目是基于Vue2.X进行开发的,那么我们先简单看一看Vue2.X是基于什么实现的吧~
Object.defineProperty
Vue2的响应式原理是基于对象的defineProperty()方法进行开发的,那么这个方法有什么作用呢?MDN是这样介绍的:
object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
也就是说,我们可以通过对象的这个方法精确的添加或者修改对象的属性。每个对象都具有get/set属性,当访问get属性时,会调用getter方法,当对象的属性值被修改时,会调用setter方法,正式基于getter和setter方法,Vue才可以利用Object.defineProperty来实现响应式系统。
Object.defineProperty在Vue中的使用
在vue中,当把一个普通的JavaScript对象传入Vue实例作为data选项,Vue会遍历此对象的所有属性,并使用object.defineProperty将这些属性转为getter/setter,
getter/setter可以追踪依赖,在属性被访问的时候通知视图变更。
Object.defineProperty(obj, 'targetObj', { get() { // 完成依赖收集 }, set() { // 发生变更,同时通知相关依赖 } })
vue3的响应式原理
vue2.0很好的实现了数据的双向绑定,但是也遗留了一个很重要的问题:由于Vue会在初始化实例时将property转化为getter/setter,所以,property必须在data对象上先存在才能让Vue将其转换为响应式数据。那么对于新增加的对象、或者某些需要特殊操作的数组想要转换为响应式数据就需要使用Vue.set等方法。
Vue3就很好的解决了这个问题。那么,Vue3是如何解决的呢?让我们就一起看看吧~
Proxy
提到Vue3的数据拦截,我们首先要了解什么是proxy?
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
原来,Vue3用了Proxy代理代替了Object.defineProperty方法。同样的,在proxy中也有get/set方法,举个例子~
var obj = new Proxy({}, { get: function (target, name) { return name; }, set: function (target, key, val) { target[key] = val return target; } });
我们通过给每一个目标对象都建立一个对应的Proxy对象对其代理就可以弥补Object.defineProperty对于新增对象无法监听的缺陷。
简单设计一个Vue3的响应系统
实现一个简单的响应系统的思路:
•读取(get)时,将副作用函数入栈;
•设置(set)时,将副作用函数出栈,执行副作用函数。
// 存储副作用函数的栈 const bucket = new Set() // 存储被注册的副作用函数 let activeEffect // 注册副作用函数 function effect (fn) { // 存储副作用函数 activeEffect = fn fn() } // 副作用函数fn effect ( () => { document.body.innerText = obj.text } )
执行匿名函数fn方法时,会触发响应式数据obj.text的读取操作,进而触发代理对象Proxy的get拦截函数:
const Proxy = new Proxy(data, { get (target, key) { if (activeEffect) { bucket.add(activeEffect) } return target[key] }, set (target, key, newVal) { target[key] = newVal bucket.forEach(fn => fn()) return true } })
到此,我们会发现,有一个疑问,我们怎样能保证修改一个属性之后触发的副作用函数是我预期想要触发的副作用函数呢?为了解决这个问题,我们还需要建立副作用函数与目标对象的联系:
我们仅需要用WeakMap代替Set数据结构:
const bucket = new WeakMap()
修改Proxy对象:
const Proxy = new Proxy(data, { get (target, key) { if (!activeEffect) return target[key] // 先从栈中取出depsMap,depsMap中保存目标对象和其相关副作用函数的一对多的关系 let depsMap = bucket.get(target) if (!depsMap) { bucket.set(target, (depsMap = new Map()) } // 再根据key从depsMap中取得deps,deps保存所有与key相关联的副作用函数 let deps = depsMap.get(key) if (!deps) { depsMap.set(key, (deps = new Set()) } deps.add(activeEffect) return target[key] }, set (target, key, newVal) { target[key] = newVal const depsMap = bucket.get(target) if (!depsMap) return const effects = depsMap.get(key) effects && effects.forEach(fn => fn()) } })
这样,我们就实现了一个简易的响应系统。那么为什么要用weakMap而不是使用Map呢?就交给大家一起思考啦~
参考文献
《Vue.js设计与实现_霍春阳》
《ECMAScript 6入门》-阮一峰

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
你也能成为“黑客”高手——趣谈Linux Shell编程语言
作者:京东零售 杜兴文 我们看过很多在电脑命令行敲一些命令并给观众展示很高科技的画面感的电影,比如《盗梦空间》《操作系统革命》《代码》等等, 再想想电影黑客帝国中的画面,估计会令很多人都叹为观止,其实挺简单的,只要会使用Linux操作系统就可以很简单地实现电脑屏幕的字符串雨了!是不是很高大上呢! 同时Linux系统的其他几个操作指令,都有十分酷炫的效果,绝对令人叹为观止,废话不多说,直接进入主题! 下面不妨逐一介绍这10个Linux比较有趣的命令。 1、1.cmatrix命令 接下来就是见证奇迹的时刻: 2、htop命令 htop是Linux操作系统的图形化性能检测工具,如果类比的话相当于windows操作系统的任务管理器 运行出来的结果是绿色的界面,同时动态的检测显示,下面看看是不是很酷的样子: 3、hollywood命令 说实话这个命令可能就是抖音里很火的那个,你眼中的程序猿VS现实中的程序猿: 执行结果如下: 4、aafire aafire终端命令可以将字符串像火焰一样的燃烧的输出 5、bastet命令 使用bastet命令可以在Linux系统下玩...
- 下一篇
程序调试利器——GDB使用指南
作者:京东科技 孙晓军 1. GDB介绍 GDB是GNU Debugger的简称,其作用是可以在程序运行时,检测程序正在做些什么。GDB程序自身是使用C和C++程序编写的,但可以支持除C和C++之外很多编程语言的调试。GDB原生支持调试的语言包含: •C •C++ •D •Go •Object-C •OpenCL C •Fortran •Pascal •Rust •Modula-2 •Ada 此外,通过扩展GDB,也可以用来调试Python语言。 使用GDB,我们可以方便地进行如下任务: •如果程序崩溃后产生了core dump文件,gdb可以通过分析core dump文件,找出程序crash的位置,调用堆栈等用于找出问题原因的关键信息 •在程序运行时,GDB可以检测当前程序正在做什么事情 •在程序运行时,修改变量的值 •可以使程序在特定条件下中断 •监视内存地址变动 •分析程序Crash后的core文件 GDB是了解三方中间件,无源码程序,解决程序疑难杂症的利器。使用GDB,可以了解程序在运行时的方方面面。尤其对于在测试(Test),集成(SIT),验收(UAT),预发布(Stag...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Linux系统CentOS6、CentOS7手动修改IP地址
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS关闭SELinux安全模块
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Hadoop3单机部署,实现最简伪集群
- CentOS6,7,8上安装Nginx,支持https2.0的开启