初始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] = valreturn target;}
});
我们通过给每一个目标对象都建立一个对应的 Proxy 对象对其代理就可以弥补 Object.defineProperty 对于新增对象无法监听的缺陷。
简单设计一个 Vue3 的响应系统
实现一个简单的响应系统的思路:
・读取(get)时,将副作用函数入栈;
・设置(set)时,将副作用函数出栈,执行副作用函数。
// 存储副作用函数的栈
const bucket = new Set()// 存储被注册的副作用函数
let activeEffect// 注册副作用函数
function effect (fn) {// 存储副作用函数activeEffect = fnfn()
}// 副作用函数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] = newValbucket.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) returnconst effects = depsMap.get(key)effects && effects.forEach(fn => fn()) }
})
这样,我们就实现了一个简易的响应系统。那么为什么要用 weakMap 而不是使用 Map 呢?就交给大家一起思考啦~
参考文献
《Vue.js 设计与实现_霍春阳》
《ECMAScript 6 入门》- 阮一峰
初始Vue响应式原理~~相关推荐
- Vue源码--解读vue响应式原理
原文链接:https://geniuspeng.github.io/2018/01/05/vue-reactivity/ Vue的官方说明里有深入响应式原理这一节.在此官方也提到过: 当你把一个普通的 ...
- Vue响应式原理详细讲解
面试官:请你简单的说说什么是Vue的响应式. 小明:mvvm就是视图模型模型视图,只有数据改变视图就会同时更新. 面试官:说的很好,回去等通知吧. 小明:.... Vue响应式原理 先看官方的说法 简 ...
- 【2019 前端进阶之路】深入 Vue 响应式原理,活捉一个 MVVM
作者:江三疯,专注前端开发.欢迎关注公众号前端发动机,第一时间获得作者文章推送,还有各类前端优质文章,致力于成为推动前端成长的引擎. 前言 作为 Vue 面试中的必考题之一,Vue 的响应式原理,想必 ...
- vue 数组删除 dome没更新_详解Vue响应式原理
摘要: 搞懂Vue响应式原理! 作者:浪里行舟 原文:深入浅出Vue响应式原理 Fundebug经授权转载,版权归原作者所有. 前言 Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是 ...
- Vue 响应式原理(双向数据绑定) 怎样实现 响应式原理?
Vue 响应式原理(双向数据绑定) 怎样实现 响应式原理? 我们在Vue里面,定义在Data里的属性,叫做响应式属性. 每一个vue组件被创建的时候,同时还有一个对象被创建出来了,这个对象我们是看不到 ...
- 手把手教你剖析vue响应式原理,监听数据不再迷茫
Object.defineProperty实现vue响应式原理 一.组件化基础 1."很久以前"的组件化 (1)asp jsp php 时代 (2)nodejs 2.数据驱动视图( ...
- Vue响应式原理的简单模型
1.前言 最近在梳理vue响应式的原理,有一些心得,值得写一篇博客出来看看. 其实之前也尝试过了解vue响应式的原理,毕竟现在面试看你用的是vue的话,基本上都会问你几句vue响应式的原理.以往学习这 ...
- Vue响应式原理(看这一篇就够了)
你肯定听说过Object.denfineProperty或是Proxy\reflect,这的确是在VUE响应式原理中起重要作用的一部分代码,但这远远不能代表整个流程的精妙.上图: 不懂没关系,请往下看 ...
- 一篇文章带你吃透VUE响应式原理
本篇响应式原理介绍比较长,全文大概1w+字.虽然内容繁杂,但阅读过后,绝对会让你对vue的响应式有更加深刻的理解. 分块阅读,效果更佳.(建议读者有一定vue使用经验和基础再食用) 首先上图,下面这张 ...
最新文章
- 资源 | 做一款炫酷的机器人需要哪些学习资源(机器人资源Awesome系列)
- Altium Designer类的使用
- go语言学习(1)map常规使用
- Linux学习总结(58)——生产环境运维故障处理指南
- LSTMs和递归神经网络的初学者指南
- Java并发编程之安全发布对象的四种方法
- python3打造专属的下载软件
- 备考OCJP认证知识点总结(一)
- matlab 2017a界面,超详细干货:matlab2017a与 CCS 6.2联调设置
- Linux AHCI驱动分析之块设备层
- params.c:Parameter() - Ignoring badly formed line in configuration file: ignore errors 解决方法
- java单点登录解决方案_N多系统单点登录,实现、解决方案。四种解决方案
- localStorage数据丢失
- 文华财经期货K线多周期画线技术,多重短线技术共振通道线指标公式——多周期主图自动画线
- 自考软考需要做什么题,自考软考真题哪里有呢?
- 习题3.6 阅读下面程序,分析其执行过程,写出输出结果
- 【Java】高效处理字符串中的标点符号
- 程序员的天堂还是地狱:论东南亚BC工厂
- deque实现生产者-消费者队列
- 机器学习 —— 简单模型的构建