首页 > 编程语言 >vue2源码分析- 数据响应简单模拟

vue2源码分析- 数据响应简单模拟

时间:2022-11-30 16:01:47浏览次数:53  
标签:依赖 函数 dep Dep 源码 vue2 data 模拟 sub

工作中大部分项目使用vue2做,但一直局限于使用,终于有闲暇时间可以学习下源码,网上优秀的源码分析很多,此文章只是记录个人所学,有问题欢迎大家指出,欢迎讨论,互相学习。

下面是我对vue2响应式数据的简单模拟,还需要亿点点补充。

vue2响应式数据原理主要通过 Object.defineProperty 数据劫持,当数据改变时,通过get方法注入依赖函数,set方执行依赖函数。

模拟效果:改变data里面的属性值后,该属性的依赖函数也会执行一次。

创建一个Dep类,Dep有一个静态值target 表示当前正在执行的函数, data里面的每个属性都有一个dep实例,dep 实例 中sub存储每个属性的依赖函数,addSub方法添加依赖函数,notify方法执行依赖函数。

export default class Dep {
  static target = null; // 全局正在执行的函数
  constructor() {
       this.sub = [];    // 存储依赖的函数
  }

  addSub(sub) {
    // 存储在当前实例中正在执行的函数
    this.sub.push(sub);
  }
  notify() {
    // 循环执行依赖的函数
    this.sub.map((item) => item.update());
  }
}

 数据响应式,遍历data,将每个属性都变成响应式,每个属性都初始化一个dep实例,当获取属性时触发get方法,收集该属性的依赖函数,修改属性值时触发set方法,执行依赖函数。

import Dep from "./dep";
function defineReactive(obj, key, val) {
  // 获取当前属性有没有自定义方法;
  let property = Object.getOwnPropertyDescriptor(obj, key);
  // 判断当前属性有没有自定义get set 方法
  let getter = property && property.get;
  let setter = property && property.set;
  // 没有val值,去obj里面的
  if ((!getter || setter) && arguments.length == 2) {
    val = obj[key];
  }

  const dep = new Dep();

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function () {
      //添加依赖函数
      if (Dep.target) {
        dep.addSub(Dep.target);
      }
      //如果有自定义方法则调用
      let value = getter ? getter.call(obj) : val;
      return value;
    },
    set: function (newVal) {
      if (setter) {
        setter.call(obj, newVal);
      } else {
        val = newVal;
      }
      //执行依赖当前属性的依赖函数
      dep.notify();
    },
  });
}

function observer(data) {
  let keys = Object.keys(data);
  for (let key of keys) {
    defineReactive(data, key);
  }
}

export { observer };

  创建Watcher 类,将依赖函数实例为一个Watcher对象,在dep实例中sub 存储的不是依赖函数,而是Watcher实例。

import Dep from "./dep";

export class Watcher {
  constructor(sub) {
    this.getter = sub; // 当前执行的函数
    this.get();
  }
  get() {
    Dep.target = this;
    this.getter.call(); // 执行函数
  }
  // 触发函数方法
  update() {
    this.get();
  }
}

  效果展示:

import { observer } from "./observer";
import { Watcher } from "./watcher";

const data = {
  test: "aa",
  test1: "cc",
};

const updateData = () => {
  console.log(data.test, "测试");
};

//Object.defineProperty 劫持数据 将数据变成响应式
observer(data);
// 注入依赖函数
new Watcher(updateData);
data.test = "bb";

  

 

标签:依赖,函数,dep,Dep,源码,vue2,data,模拟,sub
From: https://www.cnblogs.com/hardmeng/p/16938695.html

相关文章

  • 基于SpringBoot+Layui的物业管理系统【完整项目源码】
    使用建议业务逻辑简略,需要细化业务,增加业务开发,如未交费提醒等技术架构数据库:MySQL8.X后端技术:SpringBoot2.3.0,MyBatisPlus数据连接池:Druid前端技术:La......
  • HashMap源码分析(一)
    之前有写到ArrayList的源码分析,欢迎大家点开我的头像查看对于HashMap这个类大家一定不陌生,想必多多少少用过或者了解过,今天我来和大家谈谈HashMap的源码,JDK为1.8继承Abs......
  • ArrayList的源码分析(一)
    我想大家既然能看到这篇文章我就不用解释Arraylist是啥了,简单点说就是一个动态对象数组,然后就这个集合的源代码拿出来给大家分析一下我的个人看法和收获,实例代码是jdk1.8......
  • ArrayList的源码分析(二)
    上篇文章给大家介绍了arraylist集合源码的一些属性和扩容方式add方法,接下来再和大家来聊聊这个集合的一些源码首先看看remove的方法,这个方法有两个,一个是根据下标删除对......
  • Mybatis源码分析(十五) - 缓存技术
    MyBatis包含一个非常强大的查询缓存特性,使用缓存可以使应用更快地获取数据,避免频繁的数据库交互 缓存查询图: 一级缓存(也叫应用缓存)一级缓存默认会启用,想要关闭一级缓存......
  • Mybatis源码分析(十三) - 关联查询之多对多
    我的理解是,多对多其实就是两个一对多。嵌套结果:示例代码:<selectid="selectUserRole"resultMap="userRoleInfo">selecta.id,a.user_name,a.real......
  • Mybatis源码分析(十四) - discriminator 鉴别器映射
    在特定的情况下使用不同的pojo进行关联,鉴别器元素就是被设计来处理这个情况的。鉴别器非常容易理解,因为它的表现很像Java语言中的switch语句discriminator标签常用的......
  • Mybatis源码分析(十七) - 源码包分析【日志模块】
    mybatis源码下载地址:​​https://github.com/mybatis/mybatis-3​​MyBatis源码导入过程:下载MyBatis的源码检查maven的版本,必须是3.25以上,建议使用maven的最新版本mybatis的......
  • Mybatis源码分析(二十一) - 核心流程分析
    mybatis核心流程三大阶段初始化阶段读取XML配置文件和注解中的配置信息,创建配置对象,并完成各个模块的初始化的工作代理阶段封装iBatis的编程模型,使用mapper接口开发的初始化......
  • 模拟SoapUI发送XML,返回并处理逻辑(Webservice调用)
    importjava.io.BufferedReader;importjava.io.File;importjava.io.FileInputStream;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.io.Outp......