代码编织梦想

本文详细介绍了响应式原理,手把手实现Vue中的响应式

1 什么是响应式

响应式可以理解为:数据发生改变时,用到该数据的代码块自动重新执行。简而言之,就是A变,依赖A(用到A的值)的函数也跟着变

那么就需要依次考虑以下问题:

  • 1 如何监听到A值的改变?:Proxy代理set捕获器可以监听值改变
  • 2 监听到之后,重新执行用到A相关的函数,那么如何知道哪些函数用到了A?
    • 2.1 每个A都对应一个数组,里面存用到它的函数
    • 2.2 怎么知道函数用到A:
      • 将普通函数封装为响应式函数
      • 封装过程中先调用一次函数,就可以在属性get操作中捕获该函数

2 响应式函数的封装

function foo(){
	console.log(objProxy.name);
}

let activeReactiveFn = null; // 全局变量,保存当前执行的响应函数
watchFn(fn){
	activeReactiveFn = fn;
	fn(); // 执行一次 可以在用到对象的get方法中捕获
	activeReactiveFn = null;
}

3 类的封装

每个对象的属性都对应一个数组,来保存依赖它的函数。对该数组主要进行两种操作

  • 添加元素:将新的依赖函数加入数组
  • 遍历数组:数据变化时,对数组遍历,执行每个函数

由于是围绕一个数组,进行操作,所以将数组和操作封装为一个Depend类来管理
由于一个函数中可能多次用到对象的属性,只要执行一次就可以,所以要求数组中元素不能重复,因此选择Set集合来实现

class Depend {
  constructor() {
    this.reactiveFn = new Set();
  }

  depend() {
    activeReactiveFn && this.addDepend(activeReactiveFn);
  }

  addDepend(fn) {
    this.reactiveFn.add(fn);
  }

  notify() {
    this.reactiveFn.forEach((fn) => fn());
  }
}

4 数据结构的选择

每个对象的每个属性都对应一个集合,可以采用WeakMap,其中key为对象,value为map对象;每个map映射表的key保存对象的属性名,value保存对应的Depend类型对象
在这里插入图片描述
WeakMap的好处在于它对key(obj1和obj2)是弱引用,当key对象销毁时,不会影响GC对对象的回收

5 监听对象变化

Vue2—Object.defineProperty

function reactive(obj) {
  Object.keys(obj).forEach((key) => {
    let value = obj[key];
    Object.defineProperty(obj, key, {
      configurable: true,
      enumerable: true,
      get() {
        const depend = getDepend(obj, key);
        depend.depend();
        return value;
      },
      set(newValue) {
        value = newValue;
        const depend = getDepend(obj, key);
        depend.notify();
      },
    });
  });
  return obj;
}

Vue3—Proxy

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key, receiver) {
      // 收集依赖
      const depend = getDepend(target, key);
      depend.depend();
      return Reflect.get(target, key, receiver);
    },

    set(target, key, newValue, receiver) {
      Reflect.set(target, key, newValue, receiver);
      // 通知依赖
      const depend = getDepend(target, key);
      depend.notify();
    },
  });
}


6 代码设计

// 构造依赖类
class Depend {
  constructor() {
    this.reactiveFn = new Set();
  }

  depend() {
    activeReactiveFn && this.addDepend(activeReactiveFn);
  }

  addDepend(fn) {
    this.reactiveFn.add(fn);
  }

  notify() {
    this.reactiveFn.forEach((fn) => fn());
  }
}

// 查找/获取依赖
const targetMap = new WeakMap();
function getDepend(target, key) {
  let map = targetMap.get(target);
  if (!map) {
    map = new Map();
    targetMap.set(obj, map);
  }

  let depend = map.get(key);
  if (!depend) {
    depend = new Depend();
    map.set(key, depend);
  }

  return depend;
}

// 响应函数封装函数
let activeReactiveFn = null;
function watchFn(fn) {
  activeReactiveFn = fn;
  fn();
  activeReactiveFn = null;
} 

// 监听对象变化vue3(也可以替换为vue2的版本
function reactive(obj) {
  return new Proxy(obj, {
    get(target, key, receiver) {
      // 收集依赖
      const depend = getDepend(target, key);
      depend.depend();
      return Reflect.get(target, key, receiver);
    },

    set(target, key, newValue, receiver) {
      Reflect.set(target, key, newValue, receiver);
      // 通知依赖
      const depend = getDepend(target, key);
      depend.notify();
    },
  });
}

const obj = {
  name: "xs",
  age: 18,
};

function foo() {
  console.log(objProxy.name);
}

const objProxy = reactive(obj);
watchFn(foo);
// test
objProxy.name = "kobe";
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_36154157/article/details/124706157

深入浅出vue响应式原理_浪里行舟的博客-爱代码爱编程

前言 Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。这使得状态管理非常简单直接,不过理解其工作原理同样重要,这样你可以避开一些常见的问题。----官方文档 本文将针对响应式原理做一个详细介绍,并且带你实现一个基础版的响应式系统。本文代码请猛戳https://gith

深入浅出vue的响应式原理,看这一篇就够了!-爱代码爱编程

前言 Vue框架相信大家肯定很熟悉,但是每当被问到Vue数据双向绑定原理的时候,大家可能都会脱口而出:Vue 内部使用了 Object.defineProperty() 来实现数据响应式,通过这个函数可以监听到 set 和 get 的事件。这样虽然一句话把大概原理概括了,但是其内部的实现原理还是值得我们去研究的。下面我就已浅显易懂的方式带你深度解析vue

深入浅出 Vue 响应式原理-爱代码爱编程

前言 Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。这使得状态管理非常简单直接,不过理解其工作原理同样重要,这样你可以避开一些常见的问题。----官方文档 本文将针对响应式原理做一个详细介绍,并且带你实现一个基础版的响应式系统。本文代码请猛戳https://gith

《深入浅出Vue.js》读书笔记-爱代码爱编程

文章目录 Object的变化侦测如何追踪变化?如何收集依赖?依赖收集在哪里依赖是谁`Watcher`是什么如何侦测所有属性总结Array的变化侦测如何追踪变化拦截器是什么使用拦截器覆盖Array原型如何收集数组的依赖在哪里那保存数组的依赖收集依赖在拦截器中获取Observer实例侦测数组成员的变化侦测数组新增成员的变化数组的限制总结变化侦测的API

深入浅出vue.js-----(1)object的响应式-爱代码爱编程

vue会自动通过状态生成dom,然后将其输入到页面上显示出来,这个过程叫做渲染。vue的渲染过程是声明式的,我们通过模板来描述状态和dom之间的映射关系。 通常在运行时应用的内部状态是不断改变的,在改变的过程中要不断地进行重新渲染。那么要知道他们内部状态什么时候发生改变,就要进行变化侦测!变化侦测要对每个对象的每个属性进行侦测。其中的每个属性都会设置一个

深入浅出Vue.js阅读——整体流程——生命周期-爱代码爱编程

生命周期 生命周期各阶段初始化阶段模板编译阶段挂载阶段卸载阶段小结从源码角度了解生命周期new Vue()被调用时发生了什么_init方法的定义_init方法的内部原理callHook函数的实现原理errorCaptured与错误处理初始化实例属性初始化事件初始化injectprovide/inject的使用方式inject的内部原理初始化状态初始

深入浅出Vue.js阅读——整体流程——最佳实践-爱代码爱编程

最佳实践 为列表渲染设置属性`key`在`v-if`/`v-if-else/v-else`中使用`key`路由切换组件不变路由导航守卫观察`$route`对象的变化为`router-view`组件添加属性`key`为所有路由统一添加`query`使用全局守卫`beforeEach`使用函数劫持区分`Vuex`与`props`的使用边界避免`v-if

深入浅出Vue3 Composition API-爱代码爱编程

vue3改动的地方 使用Typescript放弃class采用function-based API(vue2是new Vue,vue3是createApp)option API => Composition API重构complier重构virtual DOM新的响应式机制Vue2中的跨组件重用代码方案 Mixin - 混入 代码混入其实就

深入浅出Vue响应式原理,MVVM实现过程-爱代码爱编程

   相信第一次接触Vue响应式的时候,不少同学会联想到之前学习css的时候响应式原理,即根据不同的设备、不同的宽度、不同的特性、对页面上内容的样式做出相应的调整,而Vue中的响应式并非是基于图像样式层面上的意义上的响应式,Vue中的响应式是一旦数据发生改变我们就立马通过监听器拦截知道,然后可以从中添加一些我们想要做的事,这些操作包括但是不限于发送一个网络

深入浅出 Vue 响应式原理源码剖析-爱代码爱编程

先看张图,了解一下大体流程和要做的事 初始化 在 new Vue 初始化的时候,会对我们组件的数据 props 和 data 进行初始化,由于本文主要就是介绍响应式,所以其他的不做过多说明来,看一下源码 源码地址:src/core/instance/init.js - 15行 export function initMixin (Vue: Cl

Vue3.2 响应式原理源码剖析,及与 Vue2 .x响应式的区别-爱代码爱编程

本文源码版本 Vue3.2.11,Vue2 响应式源码剖析点这里 深入浅出 Vue2 响应式原理源码剖析 我们知道相较 Vue2.x 的响应式 Vue3 对整个响应式都做了重大升级;然后 Vue3.2 相较 3.0 版本源码又做了许多变更,一起来看看吧 Vue3 和 Vue2 响应式区别 响应式性能的提升 根据8月10号尤大发布 Vue3.2 说明

学习深入浅出Vue.js(刘博文)-爱代码爱编程

1.vue.js声明式操作DOM 2.所谓渐进式框架,就是把框架分层。 最核心的部分是视图层渲染,然后往外是组件机制,在这个基础上再加入路由机制,再加入状态管理,最外层是构建工具 3.任何技术的引入都是在解决一些问题,而通常解决一个问题的同时会引起另外一个问题,这种情况更多的是做权衡,做取舍 4.Vue.js引入虚拟DOM,80%的场景变得更快了,

阅读《深入浅出vue.js》 - 1-4章笔记-爱代码爱编程

阅读《深入浅出vue.js》 - 笔记 第一章:简介 vue的发展 视图层渲染组件机制路由机制状态管理器构建打包工具vue.js是一个渐进式的javascript框架第二章:Object的变化侦测 变化侦测?什么变化了?怎么侦测?得到的效果是什么? 先来理解一下什么叫渲染:渲染是从状态生成dom,再显示到用户界面的一整套流程叫做渲染;系统或者应用

彻底理解Vue数据响应式原理-爱代码爱编程

彻底理解Vue数据响应式原理 当创建了一个实例后,通过将数据传入实例的data属性中,会将数据进行劫持,实现响应式,也就是说当这些数据发生变化时,对应的视图也会发生改变。 const data = { a: 1 } const vm = new Vue({ data: data }) console.log(vm.a === data.a);

vue响应式原理:观察者模式-爱代码爱编程

 作为计算机工程师,框架是提高开发效率的重要工具。理解框架的核心原理,有助于更好地使用它和定位问题。同时,一个优秀的框架,其设计方案和实现原理也是值得我们学习和借鉴的。本文将通过实现一个简单的响应式系统,来理解vue.js的响应式原理。 关键词:响应式原理、观察者模式、defineProperty、proxy  在vue.js中,允许用模板语

vue响应式原理_打小又皮又闹的博客-爱代码爱编程

vue响应式原理 vue响应式也叫作数据双向绑定,大致原理阐述: ​ 首先我们需要通过Object.defineProperty()方法把数据(data)设置为getter和setter的访问形式,这样我们就可以在数据被修改时在setter方法设置监视修改页面信息,也就是说每当数据被修改,就会触发对应的set方法,然后我们可以在set方法中去调用