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

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export default class Dep {
  static target = null; // 全局正在执行的函数
  constructor() {<em id="__mceDel">  }
 
  addSub(sub) {
    // 存储在当前实例中正在执行的函数
    this.sub.push(sub);
  }
  notify() {
    // 循环执行依赖的函数
    this.sub.map((item) => item.update());
  }
}
</em>
       this.sub = [];    // 存储依赖的函数

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Dep from "./dep";
 
export class Watcher {
  constructor(sub) {
    this.getter = sub; // 当前执行的函数
    this.get();
  }
  get() {
    Dep.target = this;
    this.getter.call(); // 执行函数
  }
  // 触发函数方法
  update() {
    this.get();
  }
}

  效果展示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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";

  

 

posted @   风紧了  阅读(88)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
/* 点击爆炸效果*/
/* 鼠标点击求赞文字特效 */ /*鼠标跟随效果*/
点击右上角即可分享
微信分享提示