const obj = {
a: 1,
b: 2,
c: {
name: "张三",
age: 18,
},
};
const proxyObj = reactive(obj);
export function reactive(target) {
const proxy = new Proxy(target, handlers);
return proxy;
}
//delete
export default function (target, key) {
// 判断一下目标对象上面是否有要删除的属性
const hadKey = target.hasOwnProperty(key);
// 进行删除行为
const result = Reflect.deleteProperty(target, key);
// 派发更新之前,需要判断一下
if(hadKey && result){
trigger(target, TriggerOpTypes.DELETE, key);
}
return result;
}
//get
import track from "../../effect/track.js";
import { TrackOpTypes, isObject } from "../../utils.js";
import { reactive } from "../../reactvie.js";
export default function (target, key) {
// 拦截到 get 操作后,要做一些额外的事情
// 要做的事情,就是收集依赖
track(target, TrackOpTypes.GET, key);
const result = Reflect.get(target, key);
// 获取到的成员可能是对象,需要递归处理,将其转换为响应式
if (isObject(result)) {
return reactive(result);
}
return result;
}
//has
import track from "../../effect/track.js";
import { TrackOpTypes } from "../../utils.js";
export default function (target, key) {
// 需要进行依赖的收集
track(target, TrackOpTypes.HAS, key);
return Reflect.has(target, key);
}
//ownkeys
import track from "../../effect/track.js";
import { TrackOpTypes } from "../../utils.js";
export default function (target) {
// 在此之前,因为涉及到成员的读取,所以要进行依赖收集
track(target, TrackOpTypes.ITERATE);
return Reflect.ownKeys(target);
}
//set
import trigger from "../../effect/trigger.js";
import { TriggerOpTypes, hasChanged } from "../../utils.js";
export default function (target, key, value) {
// 关于具体的操作类型需要进一步判断
// 有可能是设置,有可能是新增
const type = target.hasOwnProperty(key)
? TriggerOpTypes.SET
: TriggerOpTypes.ADD;
// 在设置之前需要缓存一下旧值
const oldValue = target[key];
// 先进行设置操作
const result = Reflect.set(target, key, value);
// 要不要派发更新需要一些判断
if (hasChanged(oldValue, value)) {
// 派发更新
trigger(target, type, key);
}
return result;
}
utils
// 提供工具方法的文件
/**
* 判断是否是对象
* @param {*} target 要判断的值
* @returns
*/
export function isObject(target) {
return typeof target === "object" && target !== null;
}
/**
* 判断值是否改变
* @param {*} oldValue
* @param {*} newValue
* @returns
*/
export function hasChanged(oldValue, newValue) {
// 使用该方法可以规避一些特殊的情况
// NaN === NaN 在 JS 中是 false,Object.is 返回的是 true
// +0 === -0 在 JS 中是 true,Object.is 返回的是 false
return !Object.is(oldValue, newValue);
}
/**
* 收集依赖的操作类型
*/
export const TrackOpTypes = {
GET: "get",
HAS: "has",
ITERATE: "iterate",
};
/**
* 触发器的操作类型
*/
export const TriggerOpTypes = {
SET: "set",
ADD: "add",
DELETE: "delete",
};
/**
* 这是一个特殊标识
*/
export const RAW = Symbol("raw");
export const ITERATE_KEY = Symbol("iterate");
effect
/**
* 用于记录当前活动的 effect
*/
export let activeEffect = undefined;
export const targetMap = new WeakMap(); // 用来存储对象和其属性的依赖关系
const effectStack = [];
/**
* 该函数的作用,是执行传入的函数,并且在执行的过程中,收集依赖
* @param {*} fn 要执行的函数
*/
export function effect(fn, options = {}) {
const { lazy = false } = options;
const environment = () => {
try {
activeEffect = environment;
effectStack.push(environment);
cleanup(environment);
return fn();
} finally {
effectStack.pop();
activeEffect = effectStack[effectStack.length - 1];
}
};
environment.deps = [];
environment.options = options;
if (!lazy) {
environment();
}
return environment;
}
export function cleanup(environment) {
let deps = environment.deps; // 拿到当前环境函数的依赖(是个数组)
if (deps.length) {
deps.forEach((dep) => {
dep.delete(environment);
});
deps.length = 0;
}
}
track
import { TrackOpTypes, ITERATE_KEY } from "../utils.js";
import { activeEffect, targetMap } from "./effect.js";
let shouldTrack = true; // 控制是否需要进行依赖收集的开关
/**
* 暂停依赖收集
*/
export function pauseTracking() {
shouldTrack = false;
}
/**
* 恢复依赖收集
*/
export function resumeTracking() {
shouldTrack = true;
}
/**
* 收集器:用于收集依赖
* @param {*} target 原始对象
* @param {*} type 进行的操作类型
* @param {*} key 针对哪一个属性
*/
export default function (target, type, key) {
// 先进行开关状态的判断
if (!shouldTrack || !activeEffect) {
return;
}
// 这里要做的事情其实很简单,就是一层一层的去找,找到了就存储
let propMap = targetMap.get(target);
if (!propMap) {
propMap = new Map();
targetMap.set(target, propMap);
}
// 之前如果是遍历所有的属性, key 会是 undefined
// 所以对 key 值做一下参数归一化
if (type === TrackOpTypes.ITERATE) {
key = ITERATE_KEY;
}
let typeMap = propMap.get(key);
if (!typeMap) {
typeMap = new Map();
propMap.set(key, typeMap);
}
// 最后一步,根据 type 值去找对应的 Set
let depSet = typeMap.get(type);
if (!depSet) {
depSet = new Set();
typeMap.set(type, depSet);
}
// 现在找到 set 集合了,就可以存储依赖了
if (!depSet.has(activeEffect)) {
depSet.add(activeEffect);
activeEffect.deps.push(depSet); // 将集合存储到 deps 数组里面
}
}
trigger
// 这是触发器
import { TriggerOpTypes, TrackOpTypes, ITERATE_KEY } from "../utils.js";
import { targetMap, activeEffect } from "./effect.js";
// 定义修改数据和触发数据的映射关系
const triggerTypeMap = {
[TriggerOpTypes.SET]: [TrackOpTypes.GET],
[TriggerOpTypes.ADD]: [
TrackOpTypes.GET,
TrackOpTypes.ITERATE,
TrackOpTypes.HAS,
],
[TriggerOpTypes.DELETE]: [
TrackOpTypes.GET,
TrackOpTypes.ITERATE,
TrackOpTypes.HAS,
],
};
/**
* 触发器
* @param {*} target 原始对象
* @param {*} type 操作的类型
* @param {*} key 操作的属性
*/
export default function (target, type, key) {
// 要做的事情很简单,就是找到依赖,然后执行依赖
const effectFns = getEffectFns(target, type, key);
if (!effectFns) return;
for (const effectFn of effectFns) {
if (effectFn === activeEffect) continue;
if (effectFn.options && effectFn.options.shcheduler) {
// 说明用户传递了回调函数,用户期望自己来处理依赖的函数
effectFn.options.shcheduler(effectFn);
} else {
// 执行依赖函数
effectFn();
}
}
}
/**
* 根据 target、type、key 这些信息找到对应的依赖函数集合
* @param {*} target
* @param {*} type
* @param {*} key
*/
function getEffectFns(target, type, key) {
const propMap = targetMap.get(target);
if (!propMap) return;
// 如果是新增或者删除操作,会涉及到额外触发迭代
const keys = [key];
if (type === TriggerOpTypes.ADD || type === TriggerOpTypes.DELETE) {
keys.push(ITERATE_KEY);
}
const effectFns = new Set(); // 用于存储依赖的函数
for (const key of keys) {
const typeMap = propMap.get(key);
if (!typeMap) continue;
const trackTypes = triggerTypeMap[type];
for (const trackType of trackTypes) {
const dep = typeMap.get(trackType);
if (!dep) continue;
for (const effectFn of dep) {
effectFns.add(effectFn);
}
}
}
return effectFns;
}