Vue.js响应式数据的简单实现方法(一看就会)

目录
  • 引言
  • 基本概念
    • 副作用函数
    • 响应式数据
  • 响应式数据的基本实现
    • 实现思路
    • 初步实现尝试
    • 完善响应系统
      • 泛化副作用函数名
      • 修复漏洞
  • 总结

引言

在Vue.js之中,Vue会自动跟踪JavaScript状态变化并在状态发生改变时响应式地更新DOM,这就是Vue.js的两大核心功能之一——响应性,是每一个Vue.js框架使用者必须熟练掌握的的功能。而得益于Vue.js自身支持的声明式渲染,Vue.js的学习成本大大降低,就算是一个前端领域的小白,只要能看懂并简单使用基本的HTML、JavaScript以及CSS,就能够很快上手Vue.js。学,确实好学;用,真的好用!但,你对Vue.js框架的内部实现原理掌握多少呢?今天,就让我们一起来简单复现一下Vue.js数据响应式。

基本概念

副作用函数

什么是副作用函数?意如其名,副作用函数指的就是会产生副作用的函数。什么是副作用呢?就是会对函数作用域外的其他部分产生影响。俗话说:是药三分毒,能治病,亦能致病。药,就有副作用,副作用函数也是。

副作用函数代码示例如下:

当effect函数执行时,它会设置body的文本内容,从而直接或间接影响到其他任何对body文本内容有所依赖的函数的执行。这就是一个简单的副作用函数。

响应式数据

以我的理解,相较“响应式数据”而言更直白的叫法应该是“副作用数据”,就好像副作用函数的执行可能会影响到函数作用域外的其他内容一样,“副作用数据”的更改可能会直接或间接影响到所有依赖该数据的函数。

假响应式数据代码示例如下:

如上图,假设每一次修改对象obj的text属性值,都会触发函数effect的重新执行,那么就可以说对象obj是一个响应式数据。当然,在这个示例里,实际上并没有实现对obj对象的数据响应。

响应式数据的基本实现

实现思路

仔细观察思考上述的例子,你可能会发现响应式数据的实现存在两个关键点:

  • 副作用函数effect的执行会触发字段obj.text的读取操作
  • 响应式数据obj.text值的修改会触发字段obj.text的设置操作

事情的脉络渐渐清晰起来:如果我们能够拦截对象obj的读取和设置操作,在副作用函数effect首次读取字段obj.text的值时将它与对象obj关联起来,此后每次重新设置字段obj.text的值,都会重新调用一次effect函数,这样不就简单的实现了对obj对象的响应吗?

初步实现尝试

实现的思路有了,那现在最关键的问题就是:如何实现拦截一个对象属性的读取和设置操作。如果你对JavaScript足够熟悉,你可能就会想到Object.defineProperty函数以及Proxy对象代理。是的,这两种方案都可以实现拦截一个对象属性的读取以及设置操作。事实上,用Object.defineProperty函数实现数据响应正是Vue.js 2中所采用的方法,而Proxy对象代理则正是Vue.js 3中所采用的方法。

接下来让我们顺着上面的思路采用proxy实现一下:

这就是采用Proxy代理对象简单实现的数据响应式,你完全可以自行创建一个副作用函数effect进行测试。当然,考虑到复杂多变的环境,此时的数据相应式还有很多继续完善的地方,让我们再加加班,尽可能地给出一个相对完美的响应式数据实现方案。

完善响应系统

泛化副作用函数名

假如有一天,副作用的函数名不叫effect了。而是叫effect1或者effect2,甚至副作用函数没有直白的名字了,变成了一个匿名函数,那么上述的响应系统方案显然是行不通的。此时,为了满足需求,我们需要提供一个用来注册副作用函数的机制,达到泛化副作用函数名的效果。

注册副作用函数名的代码示例如下:

这样,即使是一个匿名函数,也能够被成功地注册为副作用函数,注册方法如下:

当然,此时拦截数据的读取操作也需要做细微的调整:

修复漏洞

在很多时候,debug都是最头疼的,特别是明明知道有bug,但就是找不到修复的方案,那种感觉真的像在坐牢……

现在我们来考虑一个极端条件:假如,在响应式数据对象obj上添加了一个原本不存在的属性,那么会发生什么?如果你对前面的内容还不熟悉,可以再返回去翻翻代码。你会发现一个惊人的事实:在响应式数据对象obj上添加一个原本不存在的属性,会在这个新添加的属性与相关的副作用函数之间建立响应联系。冷静下来思考一下,其实,导致该问题出现的根本原因是,没有在副作用函数与被操作的目标字段之间建立明确的联系。那,该如何解决呢?

你想想,在数据结构中存不存在一种结构,它具有一一对应的关系?有,当然有,映射就是。顺着这个思路,那我们可不可以用映射的来建立目标字段与副作用函数key-value对应的关系?当然可以!那么我们就可以先把负责储存函数的变量bucket声明为一个映射Map<target, Map<key, Set()>>用来储存响应式数据(key)-该响应式数据所有属性相关的副作用函数(value),其中,Map<key, Set>储存的就是响应式对象属性与相应的副作用函数集,这样,一个明确的联系就建立起来了。而在着手优化响应代码之前,我们再想一想:bucket用WeakMap会不会比用Map要更好一点?我实话直说吧,当然应该用WeakMap,因为WeakMap的key是弱引用,不会影响到垃圾回收器的工作,会在合适的时候被回收,用在这里更合适。

具体实现代码如下:

总结

总的来说,要想实现一个响应式数据其实就是利用Proxy对象代理或者Object.defineProperty对象来拦截对数据的读取和设置操作并与相应的副作用函数作精确绑定。那么,如果现在要求你用Object.defineProperty对象来实现数据响应,你能够独立实现了吗?试一下呗!

到此这篇关于Vue.js响应式数据的简单实现方法的文章就介绍到这了,更多相关Vue.js响应式数据的实现内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 稍微学一下Vue的数据响应式(Vue2及Vue3区别)

    什么是数据响应式 从一开始使用 Vue 时,对于之前的 jq 开发而言,一个很大的区别就是基本不用手动操作 dom,data 中声明的数据状态改变后会自动重新渲染相关的 dom. 换句话说就是 Vue 自己知道哪个数据状态发生了变化及哪里有用到这个数据需要随之修改. 因此实现数据响应式有两个重点问题: 如何知道数据发生了变化? 如何知道数据变化后哪里需要修改? 对于第一个问题,如何知道数据发生了变化,Vue3 之前使用了 ES5 的一个 API Object.defineProperty Vue

  • Vue.js中provide/inject实现响应式数据更新的方法示例

    vue.js官方文档:https://cn.vuejs.org/v2/api/#provide-inject 首先假设我们在祖辈时候传入进来是个动态的数据,官方不是说如果你传入了一个可监听的对象,那么其对象还是可响应的么? parent父页面: export default { provide() { return { foo: this.fonnB } }, data(){ return { fonnB: 'old word '} } created() { setTimeout(()=>{

  • Vue3.0数据响应式原理详解

    基于Vue3.0发布在GitHub上的第一版源码(2019.10.05)整理 预备知识 ES6 Proxy,整个响应式系统的基础. 新的composition-API的基本使用,目前还没有中文文档,可以先通过这个仓库(composition-api-rfc)了解,里面也有对应的在线文档. 先把Vue3.0跑起来 先把vue-next仓库的代码clone下来,安装依赖然后构建一下,vue的package下的dist目录下找到构建的脚本,引入脚本即可. 下面一个简单计数器的DEMO: <!DOCTY

  • 浅谈Vue 数据响应式原理

    前言 Vue的数据响应主要是依赖了Object.defineProperty(),那么整个过程是怎么样的呢?以我们自己的想法来走Vue的道路,其实也就是以Vue的原理为终点,我们来逆推一下实现过程. 本文代码皆为低配版本,很多地方都不严谨,比如 if(typeof obj === 'object')这是在判断obj是否为为一个对象,虽然obj也有可能是数组等其他类型的数据,但是本文为了简便,就直接这样写来表示判断对象,对于数组使用Array.isArray(). 改造数据 我们先来尝试写一个函数

  • 谈谈对vue响应式数据更新的误解

    对于刚接触vue的同学会经常遇到数据更新了但是模板没有更新的问题,下面将结合vue的响应式特性以及异步更新机制分析常见的错误: 异步更新带来的数据响应式误解 异步数据的处理基本是一定会遇到的,处理不好就会遇到数据不更新的问题,但有一种情况是在未正确处理的情况下也能正常更新,这就会造成一种误解,详情如下所示: 模板 <div id="app"> <h2>{{dataObj.text}}</h2> </div> js new Vue({ el

  • 你了解vue3.0响应式数据怎么实现吗

    从 Proxy 说起 什么是Proxy proxy翻译过来的意思就是"代理",ES6对Proxy的定位就是target对象(原对象)的基础上通过handler增加一层"拦截",返回一个新的代理对象,之后所有在Proxy中被拦截的属性,都可以定制化一些新的流程在上面,先看一个最简单的例子 const target = {}; // 要被代理的原对象 // 用于描述代理过程的handler const handler = { get: function (target,

  • Vue.js响应式数据的简单实现方法(一看就会)

    目录 引言 基本概念 副作用函数 响应式数据 响应式数据的基本实现 实现思路 初步实现尝试 完善响应系统 泛化副作用函数名 修复漏洞 总结 引言 在Vue.js之中,Vue会自动跟踪JavaScript状态变化并在状态发生改变时响应式地更新DOM,这就是Vue.js的两大核心功能之一——响应性,是每一个Vue.js框架使用者必须熟练掌握的的功能.而得益于Vue.js自身支持的声明式渲染,Vue.js的学习成本大大降低,就算是一个前端领域的小白,只要能看懂并简单使用基本的HTML.JavaScri

  • vue.js响应式原理解析与实现

    从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很好奇vue.js是如何监测数据更新并且重新渲染页面.今天,就我们就来一步步解析vue.js响应式的原理,并且来实现一个简单的demo. 首先,先让我们来了解一些基础知识. 基础知识 Object.defineProperty es5新增了Object.defineProperty这个api,它可以允许我们为对象的属性来设定gette

  • 利用JS响应式修改vue实现页面的input值

    前言 大部分人在看到这篇文章的标题时第一时间可能有点懵,我先简单介绍一下背景: 公司有一个基于Vue实现的登录中心是我负责维护的,页面上是一个常规的登录界面,用户名输入框.密码输入框和登录按钮各一个 今天有个同事(之后简称A)过来找我问到这么一个问题: 他负责的应用将登录中心集成到了APP端,他接到的需求是希望在APP端拉起登录页面时,自动将用户帐号和密码填入,然后自动点击登录. 开始正题 我们把登录页面简化成以下代码 <template> <div> <input name

  • Vue实现双向绑定的原理以及响应式数据的方法

    一.vue中的响应式属性 Vue中的数据实现响应式绑定 1.对象实现响应式: 是在初始化的时候利用definePrototype的定义set和get过滤器,在进行组件模板编译时实现water的监听搜集依赖项,当数据发生变化时在set中通过调用dep.notify进行发布通知,实现视图的更新. 2.数组实现响应式: 对于数组则是通过继承重写数组的方法splice.pop.push.shift.unshift.sort.reverse.等可以修改原数组的方式实现响应式的,但是通过length以及直接

  • Vue.js展示AJAX数据简单示例讲解

    最近琢磨了一下vue.js,并在项目中进行了运用,感觉非常好用,强烈推荐. 当通过AJAX方式取回数据后,使用vue.js可以完美地按一定逻辑在页面上的展示数据,代码简单.优美.自然,而且便于与在用的页面框架集成. 感谢vue.js的作者,官方网站地址:https://cn.vuejs.org 举个小例子.注意,代码中使用jQuery.bootstrap.没有用过bootstrap不影响阅读本文. 一.返回的JSON数据示例 [ {"playid":"12113c676a4e

  • 茶余饭后聊聊Vue3.0响应式数据那些事儿

    "别再更新了,实在是学不动了"这句话道出了多少前端开发者的心声,"不幸"的是 Vue 的作者在国庆区间发布了 Vue3.0 的 pre-Aplha 版本,这意味着 Vue3.0 快要和我们见面了.既来之则安之,扶我起来我要开始讲了.Vue3.0 为了达到更快.更小.更易于维护.更贴近原生.对开发者更友好的目的,在很多方面进行了重构: 使用 Typescript 放弃 class 采用 function-based API 重构 complier 重构 virtual

  • solid.js响应式createSignal 源码解析

    目录 正文 createSignal readSignal writeSignal 案例分析 总结 正文 www.solidjs.com/docs/latest… createSignal 用来创建响应式数据,它可以跟踪单个值的变化. solid.js 的响应式实现参考了 S.js,它是一个体积超小的 reactive 库,支持自动收集依赖和简单的响应式编程. createSignal createSignal 首先我们来看下 createSignal 的声明: // packages/soli

  • Spring boot + mybatis + Vue.js + ElementUI 实现数据的增删改查实例代码(一)

    环境搭建 spring boot的简介 以往我们开发时用到spring总是避免不了繁琐的配置,例如我们要配置一个数据库连接,可能需要以下几步: 1.编写jdbc.properties配置文件: 2.创建spring的配置文件,加入spring配置文件前缀.配置数据库连接信息以及sqlsessionFactory等等: 3.还要在web.xml文件中加入spring的监听. springboot的出现大大简化了项目的搭建过程(spring配置以及maven配置),让我们专注于应用功能的开发,而不是

  • 通过图带你深入了解vue的响应式原理

    前言 如果自己去实现数据驱动的模式,如何解决一下几个问题: 通过什么手段去知道我的数据变了? 通过什么东西去同步更新视图? 数据劫持--obvserver 我们需要知道数据的获取和改变,数据劫持是最基础的手段.在Obeserver中,我们可以看到代码如下: Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { // ... }, set:

随机推荐