初识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入门》-阮一峰
初识VUE响应式原理的更多相关文章
- 深度解析 Vue 响应式原理
深度解析 Vue 响应式原理 该文章内容节选自团队的开源项目 InterviewMap.项目目前内容包含了 JS.网络.浏览器相关.性能优化.安全.框架.Git.数据结构.算法等内容,无论是基础还是进 ...
- Vue源码--解读vue响应式原理
原文链接:https://geniuspeng.github.io/2018/01/05/vue-reactivity/ Vue的官方说明里有深入响应式原理这一节.在此官方也提到过: 当你把一个普通的 ...
- 详解Vue响应式原理
摘要: 搞懂Vue响应式原理! 作者:浪里行舟 原文:深入浅出Vue响应式原理 Fundebug经授权转载,版权归原作者所有. 前言 Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是 ...
- vue响应式原理,去掉优化,只看核心
Vue响应式原理 作为写业务的码农,几乎不必知道原理.但是当你去找工作的时候,可是需要造原子弹的,什么都得知道一些才行.所以找工作之前可以先复习下,只要是关于vue的,必定会问响应式原理. 核心: / ...
- 深入Vue响应式原理
深入Vue.js响应式原理 一.创建一个Vue应用 new Vue({ data() { return { name: 'yjh', }; }, router, store, render: h =& ...
- vue响应式原理解析
# Vue响应式原理解析 首先定义了四个核心的js文件 - 1. observer.js 观察者函数,用来设置data的get和set函数,并且把watcher存放在dep中 - 2. watcher ...
- 浅析Vue响应式原理(三)
Vue响应式原理之defineReactive defineReactive 不论如何,最终响应式数据都要通过defineReactive来实现,实际要借助ES5新增的Object.definePro ...
- 深入解析vue响应式原理
摘要:本文主要通过结合vue官方文档及源码,对vue响应式原理进行深入分析. 1.定义 作为vue最独特的特性,响应式可以说是vue的灵魂了,表面上看就是数据发生变化后,对应的界面会重新渲染,那么响应 ...
- 浅谈vue响应式原理及发布订阅模式和观察者模式
一.Vue响应式原理 首先要了解几个概念: 数据响应式:数据模型仅仅是普通的Javascript对象,而我们修改数据时,视图会进行更新,避免了繁琐的DOM操作,提高开发效率. 双向绑定:数据改变,视图 ...
- Vue 响应式原理模拟以及最小版本的 Vue的模拟
在模拟最小的vue之前,先复习一下,发布订阅模式和观察者模式 对两种模式有了了解之后,对Vue2.0和Vue3.0的数据响应式核心原理 1.Vue2.0和Vue3.0的数据响应式核心原理 (1). ...
随机推荐
- 如何给网页和代码做HTML加密?
如何给网页和代码做HTML加密? 本篇文章给大家谈谈html混淆加密在线,以及HTML在线加密对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔. 如何给代码加密? 1.源代码加密软件推荐使 ...
- 让 K8s 更简单!8款你不得不知的 AI 工具-Part 1
介绍 最近,AI 引起了广泛关注,而 Kubernetes 驱动的 DevOps 也不例外.软件工程师是自动化的忠实拥护者,因此针对 Kubernetes 操作员的 AI 驱动工具自然也开始涌现. 这 ...
- 火山引擎数智平台的这款产品,正在帮助 APP 提升用户活跃度
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 你有没有关注过 APP 给你推送的消息? 出于提升用户活跃度的考虑,APP 会定期在应用内面向用户进行内通推送,推 ...
- Jenkins Pipeline 流水线 - 完整构建 Pipeline Script 脚本
Docker Jenkins 安装配置 Windows 2016 安装 Jenkins 前置条件可参考 Jenkins Pipeline 流水线 - 拉代码(SVN) + Maven 编译打包 Jen ...
- python jira 读取表数据批量新建子任务
小李在Jira中处理任务时,发现一个表格数据很有趣.他决定为每一行数据创建一个新的子任务.他复制粘贴,忙得不亦乐乎.同事小张路过,好奇地问:"你在做什么?"小李得意地回答:&quo ...
- 微信小程序 wx:for 遍历 Map集合
如果要在微信小程序wxml中对ES6的Map集合进行wx:for遍历,如下: let map = new Map(); map.set("a",[1,2,3]); map.set( ...
- Vue | vuex安装失败解决的方法实例
Vuex是一个专为Vue.js应用程序开发的状态管理模式 下面这篇文章主要给大家介绍了关于vuex安装失败解决的方法,文中通过图文介绍的非常详细,需要的朋友可以参考下 1.报错信息: npm ERR! ...
- 前端科普系列(3):CommonJS 不是前端却革命了前端
本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/15sedEuUVTsgyUm1lswrKA作者:Morrain 一.前言 上一篇<前端科 ...
- Webpack Vue瘦身,感受快到飞起的加载速度!
症结 在利用webpack脚手架搭建vue项目后,往往最终打包的.js和.css文件过于庞大,造成首次加载的时候白屏时间过长,影响用户体验,下图为未经任何优化直接npm run build之后的情况: ...
- C#设计模式16——中介者模式的写法
是什么: 中介者模式是一种行为型设计模式,它定义了一个中介者对象来封装一系列对象之间的交互.中介者模式可以使得对象间的交互更加松耦合,避免了对象之间的直接依赖,从而使系统更加灵活.易于扩展和维护. 为 ...