0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

简单介绍一下Vue中的响应式原理

OSC开源社区 来源:OSCHINA 社区 2023-03-13 10:11 次阅读

自从 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

// 注册副作用函数
functioneffect (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
    vue
    +关注

    关注

    0

    文章

    57

    浏览量

    7803

原文标题:初识 VUE 响应式原理

文章出处:【微信号:OSC开源社区,微信公众号:OSC开源社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Linux搭建Vue开发环境

    本文介绍在Linux环境从零开始搭建Vue开发环境的整个过程,包括vue的安装,webstorm 安装配置,devtools的安装。
    发表于 07-24 06:20

    vue简单操作

    VUE】2编写自己的第个模板页面、跳转以及简单的axios请求
    发表于 10-15 09:17

    vue中会用的插件介绍

    vue:相关插件介绍
    发表于 03-17 11:30

    vue-cli-----vue实例template:'<App/>是什么意思?

    哪位大神知道vue-cli-----vue实例template:'是什么意思吗?
    发表于 11-05 07:02

    简单介绍一下ADC

    简单介绍一下ADC:STM32F103 拥有 1~3 个 ADC(STM32F101/102 系列只有 1 个 ADC),这些 ADC 可以独立使用,也可以使用双重模式(提高采样率)。 STM32
    发表于 08-12 07:07

    介绍一下一简单易用的嵌入AI方案

    公司玩了大半年的嵌入AI平台,现在产品进入量产模式,也接触了很多嵌入方案,有了些心得体会,本人不才,在这里介绍一下一
    发表于 10-27 06:02

    简单分享一下Arduino程序编写

    编写程序代码,然后我们将程序传到Arduino电路板上,我们自己写的程序会告诉电路板我们想要做的事情,因此,被许多电子爱好者(dalao)所喜爱。最近简单了解了一下Arduino程序编写,
    发表于 01-07 08:14

    整理一下ElementUI+VUE日期控件禁用用法

    今天给大家整理一下ElementUI+VUE 日期控件禁用用法,希望对大家有所帮助!HTML文件
    发表于 01-18 09:35

    关于vue如何去水印的解决方法的介绍

    很多人都懂简单的电脑系统问题的解决方案,但是vue怎么去水印的解决思路却鲜为人知,小编前几天就遇到了vue怎么去水印的问题,于是准备整理
    发表于 03-24 17:33 3393次阅读

    简单介绍一下-Verilog-AMS的基础知识

    -Verilog-AMS,今天就简单介绍一下-Verilog-AMS。 为了便于物理系统的建模,人们在Verilog-2005的基础上,添加了些新的关键字和语法结构,由此诞生了Ver
    的头像 发表于 10-21 14:50 9737次阅读
    <b class='flag-5'>简单</b><b class='flag-5'>介绍</b><b class='flag-5'>一下</b>-Verilog-AMS的基础知识

    Vue入门之Vue定义

    Vue (读音 /vjuː/,类似于 view) 是套用于构建用户界面的渐进JavaScript框架。 Vue 的核心库只关注视图层,也就是只处理页面。
    的头像 发表于 02-06 16:41 1050次阅读
    <b class='flag-5'>Vue</b>入门之<b class='flag-5'>Vue</b>定义

    如何使用springboot+vue搭建个人网站3

    Vue.js(读音 /vjuː/, 类似于 view)是个构建数据驱动的 web 界面的渐进框架。Vue现在这么火,大家都懂。接下来让我们来认识
    的头像 发表于 02-14 16:05 1289次阅读
    如何使用springboot+<b class='flag-5'>vue</b>搭建个人网站3

    简单介绍一下什么是微波通讯?

    欢迎来到东用知识小课堂,今天东东就为大家简单介绍一下什么是微波通讯?我们通常说有三大传输系统:光纤通信、微波通信、卫星通信。实际上,卫星通信也是微波通信的种。通俗的讲电磁波通信,主要
    的头像 发表于 03-05 11:33 2212次阅读
    <b class='flag-5'>简单</b><b class='flag-5'>介绍</b><b class='flag-5'>一下</b>什么是微波通讯?

    文看懂Vue3响应系统原理

    Vue3 响应系统的实现基于 ES6 的 Proxy 对象。Proxy 可以直接监听对象和数组的变化,而无需对每个属性进行监听,从而大大提高性能。同时,Proxy 也可以解决
    的头像 发表于 12-07 10:55 1622次阅读
    <b class='flag-5'>一</b>文看懂<b class='flag-5'>Vue</b>3<b class='flag-5'>响应</b><b class='flag-5'>式</b>系统原理

    简单介绍一下电源纹波与电容啸叫

    简单介绍一下电源纹波与电容啸叫  电源纹波与电容啸叫是在电源系统中常见的两种问题,它们会影响电子设备的性能和稳定性。本篇文章将详细介绍电源纹波和电容啸叫的定义、原因、对设备的影响以及常
    的头像 发表于 02-04 09:42 969次阅读