工作中大部分项目使用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