vue2源码分析- 数据响应简单模拟
工作中大部分项目使用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";


浙公网安备 33010602011771号