万字长文详解VUE3响应式系统,你值得反复阅读,持续更新中...

163 阅读17分钟

代码路径 /node_modules/@vue/reactivity/dist/reactivity.global.js

var VueReactivity = (function (exports) {
  'use strict';

  // 创建一个Set来存储字符串中的值,用于快速查找 在后面isNonTrackableKeys中使用,作用如上1,2,3,4
  function makeMap(str, expectsLowerCase) {
    const set = new Set(str.split(","));
    return expectsLowerCase ? (val) => set.has(val.toLowerCase()) : (val) => set.has(val);
  }
  const isNonTrackableKeys = /* @__PURE__ */ makeMap(`__proto__,__v_isRef,__isVue`);

bc89e398d017c45ff8e0cf265.png 运行结果如上图

  1. makeMap 函数:这个函数接受一个字符串(以逗号分隔的键)和一个布尔值 expectsLowerCase。 它会将字符串分割成数组,并创建一个 Set,用于快速查找这些键。

  2. isNonTrackableKeys:这个常量使用 makeMap 函数创建了一个集合,包含了三个特定的键: proto、__v_isRef 和 __isVue。这些键通常在 Vue 的响应式系统中使用,但不应该被追踪。

  3. 目的:通过将这些键标记为不可追踪,Vue 可以避免在访问这些属性时触发不必要的依赖收集, 从而提高性能和避免潜在的错误。

  4. 总结来说,这段代码的目的是为了优化 Vue 的响应式系统,确保某些特定的属性不会被追踪,从而提高性能和稳定性。

  // 一些工具函数
  const NOOP = () => {};
  const extend = Object.assign;
  const hasOwnProperty$1 = Object.prototype.hasOwnProperty;
  const hasOwn = (val, key) => hasOwnProperty$1.call(val, key);
  const isArray = Array.isArray;
  const isMap = (val) => toTypeString(val) === "[object Map]";
  const isFunction = (val) => typeof val === "function";
  const isString = (val) => typeof val === "string";
  const isSymbol = (val) => typeof val === "symbol";
  const isObject = (val) => val !== null && typeof val === "object";

  // 类型判断相关函数
  const objectToString = Object.prototype.toString;
  const toTypeString = (value) => objectToString.call(value);
  const toRawType = (value) => {
    return toTypeString(value).slice(8, -1);
  };

解释:

  1. NOOP: 这是一个空函数,通常用于占位或默认回调,表示“无操作”。

  2. extend: 这是一个别名,指向 Object.assign,用于将一个或多个源对象的可枚举属性复制到目标对象。

  3. hasOwn: 这个函数检查一个对象是否具有特定的属性。它使用 hasOwnProperty 方法来判断。

  4. isArray: 这是一个简单的封装,使用 Array.isArray 来检查一个值是否为数组。

  5. isMap: 这个函数检查一个值是否为 Map 对象,通过比较其类型字符串。

  6. isFunction: 检查一个值是否为函数。

  7. isString: 检查一个值是否为字符串。

  8. isSymbol: 检查一个值是否为 Symbol 类型。

  9. isObject: 检查一个值是否为对象(非 null)。

  10. objectToString: 这是 Object.prototype.toString 的引用,用于获取对象的类型字符串。

  11. toTypeString: 这个函数调用 objectToString,返回值的类型字符串。

  12. toRawType: 这个函数从类型字符串中提取原始类型(如 Array、Object 等),通过切片操作去掉前后的 "[object " 和 "]"。

  // 判断key是否为整数字符串
  const isIntegerKey = (key) => isString(key) && key !== "NaN" && key[0] !== "-" && "" + parseInt(key, 10) === key;

  // 缓存字符串处理函数的结果
  const cacheStringFunction = (fn) => {
    const cache = Object.create(null);
    return (str) => {
      const hit = cache[str];
      return hit || (cache[str] = fn(str));
    };
  };

  // 首字母大写
  const capitalize = cacheStringFunction((str) => {
    return str.charAt(0).toUpperCase() + str.slice(1);
  });

  // 判断值是否发生变化
  const hasChanged = (value, oldValue) => !Object.is(value, oldValue);
  1. isIntegerKey:

    • 这个函数用于判断一个键是否是有效的整数键。它检查以下条件:
      • key 是字符串。
      • key 不是字符串 "NaN"。
      • key 不是负数(即不以 "-" 开头)。
      • key 转换为整数后,再转换回字符串,确保它与原始 key 相同。
  2. cacheStringFunction:

    • 这个函数用于创建一个缓存机制,以提高字符串处理函数的性能。它接受一个函数 fn 作为参数,并返回一个新的函数:
      • 当调用新函数时,它会检查缓存中是否已有该字符串的结果。
      • 如果有,直接返回缓存的结果;如果没有,则调用 fn 处理该字符串,并将结果存入缓存。
  3. capitalize:

    • 这个函数使用 cacheStringFunction 来创建一个缓存的字符串首字母大写函数。它将字符串的第一个字符转换为大写,并与剩余部分拼接。
  4. hasChanged:

    • 这个函数用于判断两个值是否不同。它使用 Object.is 方法来比较 valueoldValue,如果两者不相等,则返回 true,否则返回 false

  // 定义对象的不可枚举属性
  const def = (obj, key, value, writable = false) => {
    Object.defineProperty(obj, key, {
      configurable: true,
      enumerable: false,
      writable,
      value
    });
  };
 // 使用只有一个地方 
 function markRaw(value) {
    if (Object.isExtensible(value)) {
      def(value, "__v_skip", true);
    }
    return value;
 }

这段代码定义了一个名为 def 的函数,用于在对象 obj 上定义一个属性 key,并将其值设置为 value。具体来说:

  • Object.defineProperty 方法用于在对象上定义一个新属性或修改现有属性,并返回该对象。
  • configurable: true 表示该属性可以被删除或修改。
  • enumerable: false 表示该属性不会出现在对象的枚举属性中(例如,for...in 循环或 Object.keys())。
  • value 是要设置的属性值。

为什么不使用 Proxy

  1. 性能Object.defineProperty 在性能上通常比 Proxy 更高效,尤其是在需要频繁访问和修改属性时。
  2. 兼容性Proxy 是 ES6 引入的特性,某些旧环境可能不支持,而 Object.defineProperty 在更早的 JavaScript 版本中就可用。
  3. 简单性:在某些情况下,使用 Object.defineProperty 可以更简单地实现特定的属性行为,而不需要处理 Proxy 的复杂性。

markRaw 函数,其作用是标记一个对象为“原始”对象,防止 Vue 的响应式系统对其进行代理。

具体解释如下:

  1. 参数value 是传入的对象。
  2. Object.isExtensible(value):检查对象是否可扩展。如果对象是不可扩展的(即不能添加新属性),则返回 false
  3. def(value, "__v_skip", true):如果对象是可扩展的,则调用 def 函数在对象上定义一个名为 __v_skip 的属性,并将其值设置为 true。这个属性用于告诉 Vue 的响应式系统跳过这个对象,不对其进行代理。
  4. 返回值:最后,函数返回原始的 value 对象。

markRaw 函数的主要目的是为了优化性能,避免 Vue 对某些对象进行不必要的响应式处理。

  // 警告函数
  function warn(msg, ...args) {
    console.warn(`[Vue warn] ${msg}`, ...args);
  }

  // 以下是响应式系统的核心实现

  // 当前活跃的effect作用域
  let activeEffectScope;

  // EffectScope类,用于管理effect的生命周期
  class EffectScope {
    constructor(detached = false) {
      this.detached = detached;
      this._active = true;
      this.effects = [];
      this.cleanups = [];
      // 这行代码将当前的 EffectScope 实例的 parent 属性设置为当前活动的效果作用域(activeEffectScope)。
      //这意味着新创建的作用域会知道它的父作用域是什么
      this.parent = activeEffectScope;
      // 这个条件判断用于检查当前作用域是否是“分离的”(detached)以及是否存在一个活动的效果作用域。
      // 如果当前作用域不是分离的,并且存在一个活动的效果作用域,则执行以下代码 this.index = xxx
      if (!detached && activeEffectScope) {
      // 这行代码将当前作用域添加到父作用域的 scopes 数组中,并记录其索引。
      // activeEffectScope.scopes 是一个数组,用于存储所有子作用域。
      //push(this) 将当前作用域添加到数组中,并返回新数组的长度,因此减去 1 得到当前作用域的索引
        this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(
          this
        ) - 1;
      }
    }
    // 这是一个 getter 方法,用于返回当前作用域的 _active 属性,指示该作用域是否处于活动状态
    get active() {
      return this._active;
    }
    // 运行传入的函数,并将当前scope设置为活跃scope
    run(fn) {
      if (this._active) {
        const currentEffectScope = activeEffectScope;
        try {
          activeEffectScope = this;
          return fn();
        } finally {
          activeEffectScope = currentEffectScope;
        }
      } else {
        warn(`cannot run an inactive effect scope.`);
      }
    }
   /**
     * 该方法将当前的 EffectScope 实例设置为活动效果作用域(activeEffectScope)。
     * 这意味着在调用 on() 方法后,所有在该作用域内的响应式效果(如 effect 函数)都会被注册到当前作用域中。
     */
    on() {
      activeEffectScope = this;
    }
    //该方法将活动效果作用域(activeEffectScope)恢复为其父作用域(this.parent)。
    //这意味着在调用 off() 方法后,当前作用域将不再是活动作用域,所有在该作用域内的响应式效果将不再被追踪。
    // 这个方法应该仅在非分离的作用域(non-detached scopes)上调用,确保作用域的层级关系保持一致
    //这段代码的作用是管理当前的活动效果作用域。
    //on() 方法用于激活当前作用域,而 off() 方法则用于将活动作用域恢复到其父作用域。
    //这种机制使得 Vue 能够有效地管理和追踪响应式依赖关系
    off() {
      activeEffectScope = this.parent;
    }
    // 停止当前scope及其所有子scope
    stop(fromParent) {
      if (this._active) {
        let i, l;
        for (i = 0, l = this.effects.length; i < l; i++) {
          this.effects[i].stop();
        }
        for (i = 0, l = this.cleanups.length; i < l; i++) {
          this.cleanups[i]();
        }
        if (this.scopes) {
          for (i = 0, l = this.scopes.length; i < l; i++) {
            this.scopes[i].stop(true);
          }
        }
        // 从父scope中移除自身
        if (!this.detached && this.parent && !fromParent) {
          const last = this.parent.scopes.pop();
          if (last && last !== this) {
            this.parent.scopes[this.index] = last;
            last.index = this.index;
          }
        }
        this.parent = void 0;
        this._active = false;
      }
    }
  }

这段代码定义了一个 EffectScope 类,主要用于管理 Vue 3 中的响应式效果(reactive effects)。

  1. 构造函数

    • detached 参数用于指示该作用域是否为独立的(不与父作用域关联)。
    • this._active 表示当前作用域是否处于活动状态。
    • this.effectsthis.cleanups 分别用于存储效果和清理函数。
    • this.parent 指向当前作用域的父作用域,如果不是独立的且存在父作用域,则将当前作用域添加到父作用域的 scopes 数组中。
  2. active 属性

    • get active() 方法返回当前作用域的活动状态。
  3. run 方法

    • run(fn) 方法用于执行传入的函数 fn,在执行前将 activeEffectScope 设置为当前作用域,执行后恢复原来的作用域。如果当前作用域不活动,则会发出警告。
  4. on 和 off 方法

    • on()off() 方法用于设置和恢复 activeEffectScope,仅在非独立作用域中调用。
  5. stop 方法

    • stop(fromParent) 方法用于停止当前作用域,清理所有效果和清理函数。如果当前作用域不是独立的且有父作用域,则会更新父作用域的 scopes 数组。

EffectScope 类在 Vue 3 中用于管理响应式效果的生命周期,确保在适当的时机执行和清理这些效果。

EffectScope使用函数

function effectScope(detached) {
  return new EffectScope(detached);
}
  • effectScope 函数用于创建一个新的 EffectScope 实例。
  • 参数 detached 表示这个作用域是否是独立的(不依赖于当前的活动作用域)。
  • 返回一个新的 EffectScope 对象。
function recordEffectScope(effect, scope = activeEffectScope) {
  if (scope && scope.active) {
    scope.effects.push(effect);
  }
}
  • recordEffectScope 函数用于将一个 effect 记录到一个作用域中。
  • 参数 effect 是要记录的副作用函数。
  • 参数 scope 默认为当前活动的作用域 activeEffectScope
  • 如果 scope 存在且是活动的,则将 effect 添加到 scope.effects 数组中。
function getCurrentScope() {
  return activeEffectScope;
}
  • getCurrentScope 函数返回当前活动的作用域 activeEffectScope
  • 这是一个简单的 getter 函数,用于获取当前的作用域。
function onScopeDispose(fn) {
  if (activeEffectScope) {
    activeEffectScope.cleanups.push(fn);
  } else {
    warn(
      `onScopeDispose() is called when there is no active effect scope to be associated with.`
    );
  }
}
  • onScopeDispose 函数用于在当前作用域销毁时注册一个清理函数 fn
  • 如果当前有活动的作用域 activeEffectScope,则将 fn 添加到 activeEffectScope.cleanups 数组中。
  • 如果没有活动的作用域,则发出警告,提示 onScopeDispose 被调用时没有关联的活动作用域。

这些函数主要用于管理 Vue 3 中的副作用作用域,确保副作用在适当的时机被清理和管理。

let activeEffect;

定义一个全局变量 activeEffect,用于存储当前活动的副作用(effect)。

class ReactiveEffect {

定义一个 ReactiveEffect 类,用于管理副作用。

  constructor(fn, trigger, scheduler, scope) {
    this.fn = fn;
    this.trigger = trigger;
    this.scheduler = scheduler;
    this.active = true;
    this.deps = [];

构造函数,初始化 ReactiveEffect 实例。fn 是副作用函数,triggerscheduler 是调度相关的参数,scope 是作用域。active 表示副作用是否激活,deps 存储依赖。

    this._dirtyLevel = 4;
    this._trackId = 0;
    this._runnings = 0;
    this._shouldSchedule = false;
    this._depsLength = 0;
    recordEffectScope(this, scope);
  }

内部属性,用于管理副作用的状态和调度。_dirtyLevel 表示脏状态,_trackId 是追踪 ID,_runnings 记录运行次数,_shouldSchedule 表示是否需要调度,_depsLength 是依赖长度。recordEffectScope 函数记录副作用的作用域。

  get dirty() {
    if (this._dirtyLevel === 2 || this._dirtyLevel === 3) {
      this._dirtyLevel = 1;
      pauseTracking();
      for (let i = 0; i < this._depsLength; i++) {
        const dep = this.deps[i];
        if (dep.computed) {
          triggerComputed(dep.computed);
          if (this._dirtyLevel >= 4) {
            break;
          }
        }
      }
      if (this._dirtyLevel === 1) {
        this._dirtyLevel = 0;
      }
      resetTracking();
    }
    return this._dirtyLevel >= 4;
  }

dirty 属性的 getter 方法,用于检查和更新脏状态。如果 _dirtyLevel 为 2 或 3,则更新为 1,并暂停追踪依赖。遍历依赖数组 deps,如果依赖是计算属性,则触发计算。最后重置追踪状态。

  set dirty(v) {
    this._dirtyLevel = v ? 4 : 0;
  }

dirty 属性的 setter 方法,根据传入的值 v 更新 _dirtyLevel

  run() {
    this._dirtyLevel = 0;
    if (!this.active) {
      return this.fn();
    }
    let lastShouldTrack = shouldTrack;
    let lastEffect = activeEffect;
    try {
      shouldTrack = true;
      activeEffect = this;
      this._runnings++;
      preCleanupEffect(this);
      return this.fn();
    } finally {
      postCleanupEffect(this);
      this._runnings--;
      activeEffect = lastEffect;
      shouldTrack = lastShouldTrack;
    }
  }

run 方法,执行副作用函数 fn。如果副作用未激活,直接执行 fn。否则,更新追踪状态和当前活动副作用,执行前清理操作,执行 fn,最后执行后清理操作,恢复之前的追踪状态和活动副作用。

  stop() {
    var _a;
    if (this.active) {
      preCleanupEffect(this);
      postCleanupEffect(this);
      (_a = this.onStop) == null ? void 0 : _a.call(this);
      this.active = false;
    }
  }
}

stop 方法,停止副作用。如果副作用激活,执行前后清理操作,调用 onStop 回调(如果存在),并将 active 设置为 false

这段代码主要用于管理 Vue 3 中的响应式副作用,提供了创建、运行和停止副作用的机制。

function triggerComputed(computed) {
  return computed.value;
}

triggerComputed 函数用于触发计算属性的计算并返回其值。computed 是一个计算属性对象,computed.value 返回计算属性的当前值。

function preCleanupEffect(effect2) {
  effect2._trackId++;
  effect2._depsLength = 0;
}

preCleanupEffect 函数在清理副作用之前调用。它增加 effect2_trackId,并将 _depsLength 设为 0。_trackId 用于跟踪依赖关系的变化,_depsLength 用于记录依赖的数量。

function postCleanupEffect(effect2) {
  if (effect2.deps.length > effect2._depsLength) {
    for (let i = effect2._depsLength; i < effect2.deps.length; i++) {
      cleanupDepEffect(effect2.deps[i], effect2);
    }
    effect2.deps.length = effect2._depsLength;
  }
}

postCleanupEffect 函数在清理副作用之后调用。如果 effect2 的依赖数量大于 _depsLength,则从 _depsLength 开始遍历多余的依赖,并调用 cleanupDepEffect 函数进行清理。最后,将 effect2.deps.length 设为 _depsLength

function cleanupDepEffect(dep, effect2) {
  const trackId = dep.get(effect2);
  if (trackId !== void 0 && effect2._trackId !== trackId) {
    dep.delete(effect2);
    if (dep.size === 0) {
      dep.cleanup();
    }
  }
}

cleanupDepEffect 函数用于清理特定依赖 dep 中的 effect2。首先获取 depeffect2trackId。如果 trackId 存在且不等于 effect2._trackId,则从 dep 中删除 effect2。如果 dep 的大小为 0,则调用 dep.cleanup() 进行进一步清理。

  • triggerComputed 用于触发计算属性并返回其值。
  • preCleanupEffectpostCleanupEffect 用于在清理副作用之前和之后进行处理。
  • cleanupDepEffect 用于清理特定依赖中的副作用。
function effect(fn, options) {
  if (fn.effect instanceof ReactiveEffect) {
    fn = fn.effect.fn;
  }
  const _effect = new ReactiveEffect(fn, NOOP, () => {
    if (_effect.dirty) {
      _effect.run();
    }
  });
  if (options) {
    extend(_effect, options);
    if (options.scope)
      recordEffectScope(_effect, options.scope);
  }
  if (!options || !options.lazy) {
    _effect.run();
  }
  const runner = _effect.run.bind(_effect);
  runner.effect = _effect;
  return runner;
}
  1. function effect(fn, options) {:定义一个名为effect的函数,接收两个参数fnoptions
  2. if (fn.effect instanceof ReactiveEffect) { fn = fn.effect.fn; }:如果fn已经是一个ReactiveEffect实例,则将fn替换为其原始函数。
  3. const _effect = new ReactiveEffect(fn, NOOP, () => { if (_effect.dirty) { _effect.run(); } });:创建一个新的ReactiveEffect实例,传入fnNOOP(一个空操作函数)和一个调度函数。如果_effect标记为dirty,则运行_effect
  4. if (options) { extend(_effect, options); if (options.scope) recordEffectScope(_effect, options.scope); }:如果提供了options,则扩展_effect的属性,并记录其作用域。
  5. if (!options || !options.lazy) { _effect.run(); }:如果没有提供optionsoptions.lazyfalse,则立即运行_effect
  6. const runner = _effect.run.bind(_effect); runner.effect = _effect; return runner;:创建一个绑定到_effectrun函数,并将_effect赋值给runner.effect,最后返回runner
function stop(runner) {
  runner.effect.stop();
}
  1. function stop(runner) { runner.effect.stop(); }:定义一个名为stop的函数,接收一个runner参数,并调用其effectstop方法。
let shouldTrack = true;
let pauseScheduleStack = 0;
const trackStack = [];
  1. let shouldTrack = true;:定义一个布尔变量shouldTrack,初始值为true,用于控制是否进行依赖追踪。
  2. let pauseScheduleStack = 0;:定义一个变量pauseScheduleStack,初始值为0,用于控制调度的暂停状态。
  3. const trackStack = [];:定义一个数组trackStack,用于保存shouldTrack的状态。
function pauseTracking() {
  trackStack.push(shouldTrack);
  shouldTrack = false;
}
  1. function pauseTracking() { trackStack.push(shouldTrack); shouldTrack = false; }:定义一个名为pauseTracking的函数,将当前shouldTrack状态保存到trackStack,并将shouldTrack设置为false,暂停依赖追踪。
function enableTracking() {
  trackStack.push(shouldTrack);
  shouldTrack = true;
}
  1. function enableTracking() { trackStack.push(shouldTrack); shouldTrack = true; }:定义一个名为enableTracking的函数,将当前shouldTrack状态保存到trackStack,并将shouldTrack设置为true,启用依赖追踪。
function resetTracking() {
  const last = trackStack.pop();
  shouldTrack = last === void 0 ? true : last;
}
  1. function resetTracking() { const last = trackStack.pop(); shouldTrack = last === void 0 ? true : last; }:定义一个名为resetTracking的函数,从trackStack中弹出最后一个状态,并将shouldTrack恢复为该状态。如果trackStack为空,则将shouldTrack设置为true

这段代码主要用于管理Vue3的响应式系统中的依赖追踪和副作用处理。通过effect函数,可以创建响应式副作用,并通过pauseTrackingenableTrackingresetTracking函数来控制依赖追踪的状态。

function pauseScheduling() {
  pauseScheduleStack++;
}
  • pauseScheduling 函数的作用是增加 pauseScheduleStack 的计数。pauseScheduleStack 是一个全局变量,用于跟踪调度暂停的次数。
function resetScheduling() {
  pauseScheduleStack--;
  while (!pauseScheduleStack && queueEffectSchedulers.length) {
    queueEffectSchedulers.shift()();
  }
}
  • resetScheduling 函数的作用是减少 pauseScheduleStack 的计数。
  • 如果 pauseScheduleStack 变为 0 并且 queueEffectSchedulers 队列中有调度器,则依次执行队列中的调度器。
function trackEffect(effect2, dep, debuggerEventExtraInfo) {
  var _a;
  if (dep.get(effect2) !== effect2._trackId) {
    dep.set(effect2, effect2._trackId);
    const oldDep = effect2.deps[effect2._depsLength];
    if (oldDep !== dep) {
      if (oldDep) {
        cleanupDepEffect(oldDep, effect2);
      }
      effect2.deps[effect2._depsLength++] = dep;
    } else {
      effect2._depsLength++;
    }
    {
      (_a = effect2.onTrack) == null ? void 0 : _a.call(effect2, extend({ effect: effect2 }, debuggerEventExtraInfo));
    }
  }
}
  • trackEffect 函数用于跟踪副作用(effect)和依赖(dep)之间的关系。
  • dep.get(effect2) !== effect2._trackId 检查当前依赖是否已经跟踪了该副作用。
  • 如果没有跟踪,则 dep.set(effect2, effect2._trackId) 将副作用的 _trackId 设置到依赖中。
  • const oldDep = effect2.deps[effect2._depsLength] 获取副作用当前的依赖。
  • 如果 oldDep !== dep,则表示副作用的依赖发生了变化,需要清理旧的依赖 cleanupDepEffect(oldDep, effect2)
  • 然后将新的依赖添加到副作用的依赖数组中 effect2.deps[effect2._depsLength++] = dep
  • 如果依赖没有变化,则仅增加依赖长度 effect2._depsLength++
  • 最后,如果副作用有 onTrack 回调函数,则调用它并传递调试信息。

这段代码主要用于 Vue 3 的响应式系统,管理副作用和依赖之间的关系,确保在依赖变化时正确地重新计算副作用。

const queueEffectSchedulers = [];

定义一个数组 queueEffectSchedulers,用于存储需要调度的 effect 调度器。

function triggerEffects(dep, dirtyLevel, debuggerEventExtraInfo) {

定义一个函数 triggerEffects,它接受三个参数:

  • dep:一个依赖集合,通常是一个 Set
  • dirtyLevel:一个表示脏度级别的数值。
  • debuggerEventExtraInfo:调试器事件的额外信息。
  var _a;
  pauseScheduling();

声明一个局部变量 _a。调用 pauseScheduling 函数,暂停调度。

  for (const effect2 of dep.keys()) {

遍历 dep 集合中的每一个 effect2

    let tracking;
    if (effect2._dirtyLevel < dirtyLevel && (tracking != null ? tracking : tracking = dep.get(effect2) === effect2._trackId)) {

声明一个局部变量 tracking。如果 effect2 的脏度级别小于 dirtyLevel,并且 trackingnulldep 中的 effect2_trackIdeffect2 相等,则进入条件语句。

      effect2._shouldSchedule || (effect2._shouldSchedule = effect2._dirtyLevel === 0);
      effect2._dirtyLevel = dirtyLevel;

如果 effect2_shouldSchedulefalse,则将其设置为 effect2._dirtyLevel 是否为 0。然后将 effect2_dirtyLevel 设置为 dirtyLevel

    }
    if (effect2._shouldSchedule && (tracking != null ? tracking : tracking = dep.get(effect2) === effect2._trackId)) {

如果 effect2_shouldScheduletrue,并且 trackingnulldep 中的 effect2_trackIdeffect2 相等,则进入条件语句。

      {
        (_a = effect2.onTrigger) == null ? void 0 : _a.call(effect2, extend({ effect: effect2 }, debuggerEventExtraInfo));
      }

如果 effect2onTrigger 方法,则调用它,并传入扩展了 effect2debuggerEventExtraInfo 的对象。

      effect2.trigger();

调用 effect2trigger 方法。

      if ((!effect2._runnings || effect2.allowRecurse) && effect2._dirtyLevel !== 2) {

如果 effect2 没有运行或允许递归,并且 effect2_dirtyLevel 不等于 2,则进入条件语句。

        effect2._shouldSchedule = false;
        if (effect2.scheduler) {
          queueEffectSchedulers.push(effect2.scheduler);
        }
      }
    }
  }
  resetScheduling();
}

effect2_shouldSchedule 设置为 false。如果 effect2scheduler,则将其推入 queueEffectSchedulers 数组。最后,调用 resetScheduling 函数,重置调度。

这个函数的主要作用是遍历依赖集合 dep,根据脏度级别和调度条件,触发相应的 effect,并将需要调度的 effect 的调度器加入到 queueEffectSchedulers 数组中。

上面代码分的太散,完整版看这里对照

const queueEffectSchedulers = [];
  function triggerEffects(dep, dirtyLevel, debuggerEventExtraInfo) {
    var _a;
    pauseScheduling();
    for (const effect2 of dep.keys()) {
      let tracking;
      if (effect2._dirtyLevel < dirtyLevel && (tracking != null ? tracking : tracking = dep.get(effect2) === effect2._trackId)) {
        effect2._shouldSchedule || (effect2._shouldSchedule = effect2._dirtyLevel === 0);
        effect2._dirtyLevel = dirtyLevel;
      }
      if (effect2._shouldSchedule && (tracking != null ? tracking : tracking = dep.get(effect2) === effect2._trackId)) {
        {
          (_a = effect2.onTrigger) == null ? void 0 : _a.call(effect2, extend({ effect: effect2 }, debuggerEventExtraInfo));
        }
        effect2.trigger();
        if ((!effect2._runnings || effect2.allowRecurse) && effect2._dirtyLevel !== 2) {
          effect2._shouldSchedule = false;
          if (effect2.scheduler) {
            queueEffectSchedulers.push(effect2.scheduler);
          }
        }
      }
    }
    resetScheduling();
  }

接着看下部分

const createDep = (cleanup, computed) => {
  const dep = /* @__PURE__ */ new Map();
  dep.cleanup = cleanup;
  dep.computed = computed;
  return dep;
};
  • createDep 函数用于创建一个依赖集合 dep,它是一个 Map 对象,并且附加了 cleanupcomputed 属性。
  • cleanup 是一个清理函数,用于在依赖被删除时执行。
  • computed 是一个布尔值,表示这个依赖是否是计算属性。
const targetMap = /* @__PURE__ */ new WeakMap();
const ITERATE_KEY = Symbol("iterate");
const MAP_KEY_ITERATE_KEY = Symbol("Map key iterate");
  • targetMap 是一个 WeakMap,用于存储目标对象及其依赖关系。
  • ITERATE_KEYMAP_KEY_ITERATE_KEY 是两个 Symbol,用于标识特殊的依赖类型。
function track(target, type, key) {
  if (shouldTrack && activeEffect) {
    let depsMap = targetMap.get(target);
    if (!depsMap) {
      targetMap.set(target, depsMap = /* @__PURE__ */ new Map());
    }
    let dep = depsMap.get(key);
    if (!dep) {
      depsMap.set(key, dep = createDep(() => depsMap.delete(key)));
    }
    trackEffect(
      activeEffect,
      dep,
      {
        target,
        type,
        key
      }
    );
  }
}
  • track 函数用于追踪依赖关系。
  • shouldTrackactiveEffect 是全局变量,控制是否应该追踪依赖。
  • targetMap 中存储了目标对象 target 的依赖映射 depsMap
  • 如果 depsMap 不存在,则创建一个新的 Map 并存储在 targetMap 中。
  • depsMap 中存储了特定键 key 的依赖 dep
  • 如果 dep 不存在,则创建一个新的依赖 dep 并存储在 depsMap 中。
  • 最后,调用 trackEffect 函数,将当前的 activeEffect 添加到 dep 中。
function trigger(target, type, key, newValue, oldValue, oldTarget) {
  const depsMap = targetMap.get(target);
  if (!depsMap) {
    return;
  }
  let deps = [];
  if (type === "clear") {
    deps = [...depsMap.values()];
  } else if (key === "length" && isArray(target)) {
    const newLength = Number(newValue);
    depsMap.forEach((dep, key2) => {
      if (key2 === "length" || !isSymbol(key2) && key2 >= newLength) {
        deps.push(dep);
      }
    });
  } else {
    if (key !== void 0) {
      deps.push(depsMap.get(key));
    }
    switch (type) {
      case "add":
        if (!isArray(target)) {
          deps.push(depsMap.get(ITERATE_KEY));
          if (isMap(target)) {
            deps.push(depsMap.get(MAP_KEY_ITERATE_KEY));
          }
        } else if (isIntegerKey(key)) {
          deps.push(depsMap.get("length"));
        }
        break;
      case "delete":
        if (!isArray(target)) {
          deps.push(depsMap.get(ITERATE_KEY));
          if (isMap(target)) {
            deps.push(depsMap.get(MAP_KEY_ITERATE_KEY));
          }
        }
        break;
      case "set":
        if (isMap(target)) {
          deps.push(depsMap.get(ITERATE_KEY));
        }
        break;
    }
  }
  pauseScheduling();
  for (const dep of deps) {
    if (dep) {
      triggerEffects(
        dep,
        4,
        {
          target,
          type,
          key,
          newValue,
          oldValue,
          oldTarget
        }
      );
    }
  }
  resetScheduling();
}
  • trigger 函数用于触发依赖更新。
  • targetMap 中获取目标对象 target 的依赖映射 depsMap
  • 如果 depsMap 不存在,直接返回。
  • 根据不同的 typekey,收集需要触发的依赖 deps
    • 如果 type 是 "clear",收集所有依赖。
    • 如果 key 是 "length" 且目标是数组,根据新长度收集依赖。
    • 根据 typekey 的不同情况,收集特定的依赖。
  • 暂停调度,遍历收集到的依赖 deps,调用 triggerEffects 函数触发依赖更新。
  • 最后,重置调度。

这段代码主要用于 Vue 3 的响应式系统,追踪和触发依赖关系,以实现数据变化时的自动更新。

function getDepFromReactive(object, key) {
  var _a;
  return (_a = targetMap.get(object)) == null ? void 0 : _a.get(key);
}
  • getDepFromReactive 函数用于从 targetMap 中获取与 objectkey 相关的依赖。
  • targetMap 是一个 WeakMap,用于存储对象及其依赖关系。
  • object 是目标对象,key 是对象的属性。
  • 通过 targetMap.get(object) 获取与 object 相关的依赖映射,如果不存在则返回 undefined
  • 如果存在,则返回与 key 相关的依赖。
const isNonTrackableKeys = /* @__PURE__ */ makeMap(`__proto__,__v_isRef,__isVue`);
  • isNonTrackableKeys 是一个包含不可追踪键的集合。
  • makeMap 是一个工具函数,用于创建一个快速查找的键值对集合。
  • 这些键包括 __proto____v_isRef__isVue,它们不应该被追踪。
const builtInSymbols = new Set(
  /* @__PURE__ */ Object.getOwnPropertyNames(Symbol).filter((key) => key !== "arguments" && key !== "caller").map((key) => Symbol[key]).filter(isSymbol)
);
  • builtInSymbols 是一个包含所有内置符号的集合。
  • Object.getOwnPropertyNames(Symbol) 获取 Symbol 对象的所有属性名。
  • 过滤掉 argumentscaller 属性。
  • 将剩余的属性名映射为 Symbol 对象。
  • 过滤出所有符号类型的属性。
const arrayInstrumentations = /* @__PURE__ */ createArrayInstrumentations();
  • arrayInstrumentations 是一个包含数组方法的增强版对象。
  • 这些方法在调用时会自动进行依赖追踪和调度。
function createArrayInstrumentations() {
  const instrumentations = {};
  ["includes", "indexOf", "lastIndexOf"].forEach((key) => {
    instrumentations[key] = function(...args) {
      const arr = toRaw(this);
      for (let i = 0, l = this.length; i < l; i++) {
        track(arr, "get", i + "");
      }
      const res = arr[key](...args);
      if (res === -1 || res === false) {
        return arr[key](...args.map(toRaw));
      } else {
        return res;
      }
    };
  });
  ["push", "pop", "shift", "unshift", "splice"].forEach((key) => {
    instrumentations[key] = function(...args) {
      pauseTracking();
      pauseScheduling();
      const res = toRaw(this)[key].apply(this, args);
      resetScheduling();
      resetTracking();
      return res;
    };
  });
  return instrumentations;
}
  • createArrayInstrumentations 函数创建一个包含增强版数组方法的对象。
  • instrumentations 对象存储这些增强版方法。
  • 对于 includesindexOflastIndexOf 方法:
    • this 转换为原始数组 arr
    • 遍历数组并追踪每个元素的 get 操作。
    • 调用原始数组方法,如果结果为 -1false,则对参数进行原始转换后再次调用。
  • 对于 pushpopshiftunshiftsplice 方法:
    • 暂停依赖追踪和调度。
    • 调用原始数组方法。
    • 恢复调度和追踪。
function hasOwnProperty(key) {
  const obj = toRaw(this);
  track(obj, "has", key);
  return obj.hasOwnProperty(key);
}
  • hasOwnProperty 函数用于检查对象是否具有某个属性。
  • this 转换为原始对象 obj
  • 追踪 objhas 操作。
  • 返回 obj 是否具有 key 属性。

好的,我会逐行详细解释这段Vue 3代码的作用。

class BaseReactiveHandler {
  constructor(_isReadonly = false, _isShallow = false) {
    this._isReadonly = _isReadonly;
    this._isShallow = _isShallow;
  }
  get(target, key, receiver) {
    const isReadonly2 = this._isReadonly, isShallow2 = this._isShallow;
    if (key === "__v_isReactive") {
      return !isReadonly2;
    } else if (key === "__v_isReadonly") {
      return isReadonly2;
    } else if (key === "__v_isShallow") {
      return isShallow2;
    } else if (key === "__v_raw") {
      if (receiver === (isReadonly2 ? isShallow2 ? shallowReadonlyMap : readonlyMap : isShallow2 ? shallowReactiveMap : reactiveMap).get(target) || 
      Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)) {
        return target;
      }
      return;
    }
    const targetIsArray = isArray(target);
    if (!isReadonly2) {
      if (targetIsArray && hasOwn(arrayInstrumentations, key)) {
        return Reflect.get(arrayInstrumentations, key, receiver);
      }
      if (key === "hasOwnProperty") {
        return hasOwnProperty;
      }
    }
    const res = Reflect.get(target, key, receiver);
    if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {
      return res;
    }
    if (!isReadonly2) {
      track(target, "get", key);
    }
    if (isShallow2) {
      return res;
    }
    if (isRef(res)) {
      return targetIsArray && isIntegerKey(key) ? res : res.value;
    }
    if (isObject(res)) {
      return isReadonly2 ? readonly(res) : reactive(res);
    }
    return res;
  }
}

解释

  1. class BaseReactiveHandler: 定义了一个基础的响应式处理器类。
  2. constructor(_isReadonly = false, _isShallow = false): 构造函数,初始化两个属性 _isReadonly_isShallow,分别表示是否只读和是否浅层响应。
  3. get(target, key, receiver): 拦截对象属性的读取操作。
    • const isReadonly2 = this._isReadonly, isShallow2 = this._isShallow: 将类的属性赋值给局部变量。
    • if (key === "__v_isReactive"): 检查是否请求 __v_isReactive 属性,返回是否不是只读。
    • else if (key === "__v_isReadonly"): 检查是否请求 __v_isReadonly 属性,返回是否只读。
    • else if (key === "__v_isShallow"): 检查是否请求 __v_isShallow 属性,返回是否浅层响应。
    • else if (key === "__v_raw"): 检查是否请求 __v_raw 属性,返回原始对象。
    • const targetIsArray = isArray(target): 检查目标对象是否是数组。
    • if (!isReadonly2): 如果不是只读的,处理数组和 hasOwnProperty 的特殊情况。
    • const res = Reflect.get(target, key, receiver): 使用 Reflect.get 获取属性值。
    • if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)): 检查是否是内置符号或不可追踪的键。
    • if (!isReadonly2): 如果不是只读的,追踪属性读取。
    • if (isShallow2): 如果是浅层响应,直接返回结果。
    • if (isRef(res)): 如果结果是 ref,返回其值。
    • if (isObject(res)): 如果结果是对象,递归处理为响应式或只读对象。
    • return res: 返回结果。
class MutableReactiveHandler extends BaseReactiveHandler {
  constructor(isShallow2 = false) {
    super(false, isShallow2);
  }
  set(target, key, value, receiver) {
    let oldValue = target[key];
    if (!this._isShallow) {
      const isOldValueReadonly = isReadonly(oldValue);
      if (!isShallow(value) && !isReadonly(value)) {
        oldValue = toRaw(oldValue);
        value = toRaw(value);
      }
      if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
        if (isOldValueReadonly) {
          return false;
        } else {
          oldValue.value = value;
          return true;
        }
      }
    }
    const hadKey = isArray(target) && isIntegerKey(key) ? Number(key) < target.length : hasOwn(target, key);
    const result = Reflect.set(target, key, value, receiver);
    if (target === toRaw(receiver)) {
      if (!hadKey) {
        trigger(target, "add", key, value);
      } else if (hasChanged(value, oldValue)) {
        trigger(target, "set", key, value, oldValue);
      }
    }
    return result;
  }
}

解释

  1. class MutableReactiveHandler extends BaseReactiveHandler: 定义了一个可变的响应式处理器类,继承自 BaseReactiveHandler
  2. constructor(isShallow2 = false): 构造函数,调用父类构造函数,初始化是否浅层响应。
  3. set(target, key, value, receiver): 拦截对象属性的设置操作。
    • let oldValue = target[key]: 获取旧值。
    • if (!this._isShallow): 如果不是浅层响应,处理只读和 ref 的特殊情况。
    • const hadKey = isArray(target) && isIntegerKey(key) ? Number(key) < target.length : hasOwn(target, key): 检查目标对象是否已有该键。
    • const result = Reflect.set(target, key, value, receiver): 使用 Reflect.set 设置属性值。
    • if (target === toRaw(receiver)): 如果目标对象是原始对象,触发相应的响应式更新。
    • return result: 返回设置结果。

这段代码主要实现了Vue 3响应式系统中的核心逻辑,通过代理对象的 getset 操作,实现对对象属性的响应式追踪和更新。

好的,以下是对选中代码的逐行详细解释:

deleteProperty(target, key) {
  const hadKey = hasOwn(target, key); // 检查目标对象是否拥有该属性
  const oldValue = target[key]; // 保存旧值
  const result = Reflect.deleteProperty(target, key); // 使用Reflect.deleteProperty删除属性
  if (result && hadKey) {
    trigger(target, "delete", key, void 0, oldValue); // 如果删除成功且原来有该属性,触发“delete”操作
  }
  return result; // 返回删除操作的结果
}
  • deleteProperty 方法用于拦截对对象属性的删除操作。
  • hasOwn 检查目标对象是否拥有该属性。
  • Reflect.deleteProperty 实际执行删除操作。
  • 如果删除成功且原来有该属性,调用 trigger 函数触发相应的反应。
has(target, key) {
  const result = Reflect.has(target, key); // 使用Reflect.has检查属性是否存在
  if (!isSymbol(key) || !builtInSymbols.has(key)) {
    track(target, "has", key); // 如果key不是Symbol或不是内置Symbol,追踪“has”操作
  }
  return result; // 返回检查结果
}
  • has 方法用于拦截对对象属性存在性的检查。
  • Reflect.has 实际执行检查操作。
  • 如果 key 不是 Symbol 或不是内置 Symbol,调用 track 函数追踪“has”操作。
ownKeys(target) {
  track(
    target,
    "iterate",
    isArray(target) ? "length" : ITERATE_KEY // 如果目标是数组,追踪“length”操作,否则追踪“iterate”操作
  );
  return Reflect.ownKeys(target); // 返回目标对象的所有属性键
}
  • ownKeys 方法用于拦截对对象所有属性键的获取操作。
  • track 函数追踪“iterate”操作,如果目标是数组,则追踪“length”操作。
  • Reflect.ownKeys 实际获取所有属性键。
class ReadonlyReactiveHandler extends BaseReactiveHandler {
  constructor(isShallow2 = false) {
    super(true, isShallow2); // 调用父类构造函数,设置为只读
  }
  set(target, key) {
    {
      warn(
        `Set operation on key "${String(key)}" failed: target is readonly.`,
        target
      ); // 警告:尝试设置只读对象的属性
    }
    return true; // 返回true,表示设置操作失败
  }
  deleteProperty(target, key) {
    {
      warn(
        `Delete operation on key "${String(key)}" failed: target is readonly.`,
        target
      ); // 警告:尝试删除只读对象的属性
    }
    return true; // 返回true,表示删除操作失败
  }
}
  • ReadonlyReactiveHandler 类继承自 BaseReactiveHandler,用于处理只读的响应式对象。
  • 构造函数 constructor 调用父类构造函数,设置 isReadonlytrue
  • set 方法拦截对只读对象属性的设置操作,发出警告并返回 true 表示操作失败。
  • deleteProperty 方法拦截对只读对象属性的删除操作,发出警告并返回 true 表示操作失败。

这些代码主要用于 Vue 3 的响应式系统,处理对象属性的设置、删除和检查操作,并在只读模式下发出警告。

const mutableHandlers = /* @__PURE__ */ new MutableReactiveHandler();
const readonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler();
const shallowReactiveHandlers = /* @__PURE__ */ new MutableReactiveHandler(true);
const shallowReadonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler(true);
  • 这几行代码创建了四个处理器对象,用于处理不同类型的响应式数据:
    • mutableHandlers:用于处理可变的响应式数据。
    • readonlyHandlers:用于处理只读的响应式数据。
    • shallowReactiveHandlers:用于处理浅层可变的响应式数据。
    • shallowReadonlyHandlers:用于处理浅层只读的响应式数据。
const toShallow = (value) => value;
const getProto = (v) => Reflect.getPrototypeOf(v);
  • toShallow:一个简单的函数,直接返回传入的值,用于浅层处理。
  • getProto:使用Reflect.getPrototypeOf获取对象的原型。
function get(target, key, isReadonly = false, isShallow = false) {
  target = target["__v_raw"];
  const rawTarget = toRaw(target);
  const rawKey = toRaw(key);
  if (!isReadonly) {
    if (hasChanged(key, rawKey)) {
      track(rawTarget, "get", key);
    }
    track(rawTarget, "get", rawKey);
  }
  const { has: has2 } = getProto(rawTarget);
  const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;
  if (has2.call(rawTarget, key)) {
    return wrap(target.get(key));
  } else if (has2.call(rawTarget, rawKey)) {
    return wrap(target.get(rawKey));
  } else if (target !== rawTarget) {
    target.get(key);
  }
}
  • get函数用于获取目标对象的属性值:
    • target = target["__v_raw"]:获取原始对象。
    • toRaw:将响应式对象转换为原始对象。
    • track:用于依赖收集,跟踪属性的读取。
    • getProto:获取对象的原型。
    • wrap:根据是否浅层或只读,选择合适的包装函数。
    • has2.call(rawTarget, key):检查原始对象是否有该属性。
    • wrap(target.get(key)):返回包装后的属性值。
function has(key, isReadonly = false) {
  const target = this["__v_raw"];
  const rawTarget = toRaw(target);
  const rawKey = toRaw(key);
  if (!isReadonly) {
    if (hasChanged(key, rawKey)) {
      track(rawTarget, "has", key);
    }
    track(rawTarget, "has", rawKey);
  }
  return key === rawKey ? target.has(key) : target.has(key) || target.has(rawKey);
}
  • has函数用于检查目标对象是否包含某个属性:
    • target = this["__v_raw"]:获取原始对象。
    • toRaw:将响应式对象转换为原始对象。
    • track:用于依赖收集,跟踪属性的检查。
    • return key === rawKey ? target.has(key) : target.has(key) || target.has(rawKey):返回属性是否存在。
function size(target, isReadonly = false) {
  target = target["__v_raw"];
  !isReadonly && track(toRaw(target), "iterate", ITERATE_KEY);
  return Reflect.get(target, "size", target);
}
  • size函数用于获取目标对象的大小:
    • target = target["__v_raw"]:获取原始对象。
    • track:用于依赖收集,跟踪迭代操作。
    • Reflect.get(target, "size", target):使用Reflect.get获取对象的size属性。
function add(value) {
  value = toRaw(value);
  const target = toRaw(this);
  const proto = getProto(target);
  const hadKey = proto.has.call(target, value);
  if (!hadKey) {
    target.add(value);
    trigger(target, "add", value, value);
  }
  return this;
}
  • add函数用于向目标对象添加一个值:
    • value = toRaw(value):将值转换为原始值。
    • target = toRaw(this):将目标对象转换为原始对象。
    • proto.has.call(target, value):检查目标对象是否已经包含该值。
    • target.add(value):添加值到目标对象。
    • trigger(target, "add", value, value):触发添加操作的响应。
function set(key, value) {
  value = toRaw(value);
  const target = toRaw(this);
  const { has: has2, get: get2 } = getProto(target);
  let hadKey = has2.call(target, key);
  if (!hadKey) {
    key = toRaw(key);
    hadKey = has2.call(target, key);
  } else {
    checkIdentityKeys(target, has2, key);
  }
  const oldValue = get2.call(target, key);
  target.set(key, value);
  if (!hadKey) {
    trigger(target, "add", key, value);
  } else if (hasChanged(value, oldValue)) {
    trigger(target, "set", key, value, oldValue);
  }
  return this;
}
  • set函数用于设置目标对象的属性值:
    • value = toRaw(value):将值转换为原始值。
    • target = toRaw(this):将目标对象转换为原始对象。
    • has2.call(target, key):检查目标对象是否已经包含该键。
    • get2.call(target, key):获取旧值。
    • target.set(key, value):设置新值。
    • trigger(target, "add", key, value):触发添加操作的响应。
    • trigger(target, "set", key, value, oldValue):触发设置操作的响应。

这段代码主要用于实现Vue 3中的响应式系统,通过对对象的操作进行拦截和处理,实现数据的响应式更新。

function deleteEntry(key) {
  const target = toRaw(this);
  const { has: has2, get: get2 } = getProto(target);
  let hadKey = has2.call(target, key);
  if (!hadKey) {
    key = toRaw(key);
    hadKey = has2.call(target, key);
  } else {
    checkIdentityKeys(target, has2, key);
  }
  const oldValue = get2 ? get2.call(target, key) : void 0;
  const result = target.delete(key);
  if (hadKey) {
    trigger(target, "delete", key, void 0, oldValue);
  }
  return result;
}

deleteEntry 函数

  1. const target = toRaw(this);: 将 this 转换为原始对象。
  2. const { has: has2, get: get2 } = getProto(target);: 获取对象的原型方法 hasget
  3. let hadKey = has2.call(target, key);: 检查 target 是否有 key
  4. if (!hadKey) { key = toRaw(key); hadKey = has2.call(target, key); }: 如果没有 key,将 key 转换为原始值并再次检查。
  5. else { checkIdentityKeys(target, has2, key); }: 否则,检查键的身份。
  6. const oldValue = get2 ? get2.call(target, key) : void 0;: 获取旧值。
  7. const result = target.delete(key);: 删除 key
  8. if (hadKey) { trigger(target, "delete", key, void 0, oldValue); }: 如果有 key,触发删除操作。
  9. return result;: 返回删除结果。
function clear() {
  const target = toRaw(this);
  const hadItems = target.size !== 0;
  const oldTarget = isMap(target) ? new Map(target) : new Set(target);
  const result = target.clear();
  if (hadItems) {
    trigger(target, "clear", void 0, void 0, oldTarget);
  }
  return result;
}

clear 函数

  1. const target = toRaw(this);: 将 this 转换为原始对象。
  2. const hadItems = target.size !== 0;: 检查 target 是否有元素。
  3. const oldTarget = isMap(target) ? new Map(target) : new Set(target);: 复制 target
  4. const result = target.clear();: 清空 target
  5. if (hadItems) { trigger(target, "clear", void 0, void 0, oldTarget); }: 如果有元素,触发清空操作。
  6. return result;: 返回清空结果。
function createForEach(isReadonly, isShallow) {
  return function forEach(callback, thisArg) {
    const observed = this;
    const target = observed["__v_raw"];
    const rawTarget = toRaw(target);
    const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;
    !isReadonly && track(rawTarget, "iterate", ITERATE_KEY);
    return target.forEach((value, key) => {
      return callback.call(thisArg, wrap(value), wrap(key), observed);
    });
  };
}

createForEach 函数

  1. return function forEach(callback, thisArg) {: 返回一个 forEach 函数。
  2. const observed = this;: 获取当前对象。
  3. const target = observed["__v_raw"];: 获取原始对象。
  4. const rawTarget = toRaw(target);: 将 target 转换为原始对象。
  5. const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;: 根据参数选择包装函数。
  6. !isReadonly && track(rawTarget, "iterate", ITERATE_KEY);: 如果不是只读,追踪迭代操作。
  7. return target.forEach((value, key) => { return callback.call(thisArg, wrap(value), wrap(key), observed); });: 调用 forEach 并包装值和键。
function createIterableMethod(method, isReadonly, isShallow) {
  return function(...args) {
    const target = this["__v_raw"];
    const rawTarget = toRaw(target);
    const targetIsMap = isMap(rawTarget);
    const isPair = method === "entries" || method === Symbol.iterator && targetIsMap;
    const isKeyOnly = method === "keys" && targetIsMap;
    const innerIterator = target[method](...args);
    const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;
    !isReadonly && track(rawTarget, "iterate", isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY);
    return {
      next() {
        const { value, done } = innerIterator.next();
        return done ? { value, done } : {
          value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value),
          done
        };
      },
      [Symbol.iterator]() {
        return this;
      }
    };
  };
}

createIterableMethod 函数

  1. return function(...args) {: 返回一个可迭代方法。
  2. const target = this["__v_raw"];: 获取原始对象。
  3. const rawTarget = toRaw(target);: 将 target 转换为原始对象。
  4. const targetIsMap = isMap(rawTarget);: 检查 target 是否为 Map
  5. const isPair = method === "entries" || method === Symbol.iterator && targetIsMap;: 检查是否为键值对。
  6. const isKeyOnly = method === "keys" && targetIsMap;: 检查是否仅为键。
  7. const innerIterator = target[method](...args);: 获取内部迭代器。
  8. const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;: 根据参数选择包装函数。
  9. !isReadonly && track(rawTarget, "iterate", isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY);: 如果不是只读,追踪迭代操作。
  10. return { next() { const { value, done } = innerIterator.next(); return done ? { value, done } : { value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), done }; }, [Symbol.iterator]() { return this; } };: 返回一个迭代器对象。
function createReadonlyMethod(type) {
  return function(...args) {
    {
      const key = args[0] ? `on key "${args[0]}" ` : ``;
      warn(`${capitalize(type)} operation ${key}failed: target is readonly.`, toRaw(this));
    }
    return type === "delete" ? false : type === "clear" ? void 0 : this;
  };
}

createReadonlyMethod 函数

  1. return function(...args) {: 返回一个只读方法。
  2. const key = args[0] ? on key "${args[0]}" : ``;: 获取键。
  3. warn(capitalize(type)operation{capitalize(type)} operation {key}failed: target is readonly., toRaw(this));: 警告只读操作失败。
  4. return type === "delete" ? false : type === "clear" ? void 0 : this;: 返回操作结果。
function createInstrumentations() {
  const mutableInstrumentations2 = {
    get(key) {
      return get(this, key);
    },
    get size() {
      return size(this);
    },
    has,
    add,
    set,
    delete: deleteEntry,
    clear,
    forEach: createForEach(false, false)
  };
  const shallowInstrumentations2 = {
    get(key) {
      return get(this, key, false, true);
    },
    get size() {
      return size(this);
    },
    has,
    add,
    set,
    delete: deleteEntry,
    clear,
    forEach: createForEach(false, true)
  };
  const readonlyInstrumentations2 = {
    get(key) {
      return get(this, key, true);
    },
    get size() {
      return size(this, true);
    },
    has(key) {
      return has.call(this, key, true);
    },
    add: createReadonlyMethod("add"),
    set: createReadonlyMethod("set"),
    delete: createReadonlyMethod("delete"),
    clear: createReadonlyMethod("clear"),
    forEach: createForEach(true, false)
  };
  const shallowReadonlyInstrumentations2 = {
    get(key) {
      return get(this, key, true, true);
    },
    get size() {
      return size(this, true);
    },
    has(key) {
      return has.call(this, key, true);
    },
    add: createReadonlyMethod("add"),
    set: createReadonlyMethod("set"),
    delete: createReadonlyMethod("delete"),
    clear: createReadonlyMethod("clear"),
    forEach: createForEach(true, true)
  };
  const iteratorMethods = ["keys", "values", "entries", Symbol.iterator];
  iteratorMethods.forEach((method) => {
    mutableInstrumentations2[method] = createIterableMethod(method, false, false);
    readonlyInstrumentations2[method] = createIterableMethod(method, true, false);
    shallowInstrumentations2[method] = createIterableMethod(method, false, true);
    shallowReadonlyInstrumentations2[method] = createIterableMethod(method, true, true);
  });
  return [
    mutableInstrumentations2,
    readonlyInstrumentations2,
    shallowInstrumentations2,
    shallowReadonlyInstrumentations2
  ];
}

createInstrumentations 函数

  1. const mutableInstrumentations2 = { ... }: 创建可变操作集合。
  2. const shallowInstrumentations2 = { ... }: 创建浅层可变操作集合。
  3. const readonlyInstrumentations2 = { ... }: 创建只读操作集合。
  4. const shallowReadonlyInstrumentations2 = { ... }: 创建浅层只读操作集合。
  5. const iteratorMethods = ["keys", "values", "entries", Symbol.iterator];: 定义迭代方法。
  6. iteratorMethods.forEach((method) => { ... });: 为每个迭代方法创建相应的操作。
  7. return [ mutableInstrumentations2, readonlyInstrumentations2, shallowInstrumentations2, shallowReadonlyInstrumentations2 ];: 返回所有操作集合。

这段代码主要是为 Vue 3 的响应式系统创建各种操作方法,包括删除、清空、迭代和只读操作。通过这些方法,Vue 3 可以更高效地管理响应式数据。

  const [
    mutableInstrumentations,
    readonlyInstrumentations,
    shallowInstrumentations,
    shallowReadonlyInstrumentations
  ] = /* @__PURE__ */ createInstrumentations();

这段代码调用 createInstrumentations 函数,并将返回的结果解构赋值给四个常量:mutableInstrumentationsreadonlyInstrumentationsshallowInstrumentationsshallowReadonlyInstrumentations。这些常量分别代表可变、只读、浅层可变和浅层只读的操作集合。

  function createInstrumentationGetter(isReadonly, shallow) {
    const instrumentations = shallow ? isReadonly ? shallowReadonlyInstrumentations : shallowInstrumentations : isReadonly ? readonlyInstrumentations : mutableInstrumentations;

createInstrumentationGetter 是一个工厂函数,用于创建一个 getter 函数。它根据 isReadonlyshallow 参数选择合适的操作集合。

    return (target, key, receiver) => {
      if (key === "__v_isReactive") {
        return !isReadonly;
      } else if (key === "__v_isReadonly") {
        return isReadonly;
      } else if (key === "__v_raw") {
        return target;
      }

返回的 getter 函数会根据 key 的不同返回不同的值。如果 key__v_isReactive,则返回 !isReadonly;如果 key__v_isReadonly,则返回 isReadonly;如果 key__v_raw,则返回原始对象 target

      return Reflect.get(
        hasOwn(instrumentations, key) && key in target ? instrumentations : target,
        key,
        receiver
      );
    };
  }

对于其他的 key,使用 Reflect.getinstrumentationstarget 中获取值。hasOwn 函数用于检查 instrumentations 是否有这个 key

  const mutableCollectionHandlers = {
    get: /* @__PURE__ */ createInstrumentationGetter(false, false)
  };
  const shallowCollectionHandlers = {
    get: /* @__PURE__ */ createInstrumentationGetter(false, true)
  };
  const readonlyCollectionHandlers = {
    get: /* @__PURE__ */ createInstrumentationGetter(true, false)
  };
  const shallowReadonlyCollectionHandlers = {
    get: /* @__PURE__ */ createInstrumentationGetter(true, true)
  };

这几行代码定义了四种不同的集合处理器,分别用于可变、浅层可变、只读和浅层只读的集合。每个处理器的 get 方法都是通过 createInstrumentationGetter 创建的。

  function checkIdentityKeys(target, has2, key) {
    const rawKey = toRaw(key);
    if (rawKey !== key && has2.call(target, rawKey)) {
      const type = toRawType(target);
      warn(
        `Reactive ${type} contains both the raw and reactive versions of the same object${type === `Map` ? ` as keys` : ``}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.`
      );
    }
  }

checkIdentityKeys 函数用于检查目标对象中是否同时存在原始和响应式版本的同一个对象。如果存在,会发出警告,提示可能导致不一致性。

  const reactiveMap = /* @__PURE__ */ new WeakMap();
  const shallowReactiveMap = /* @__PURE__ */ new WeakMap();
  const readonlyMap = /* @__PURE__ */ new WeakMap();
  const shallowReadonlyMap = /* @__PURE__ */ new WeakMap();

这几行代码定义了四个 WeakMap,分别用于存储可变、浅层可变、只读和浅层只读的响应式对象。

  function targetTypeMap(rawType) {
    switch (rawType) {
      case "Object":
      case "Array":
        return 1 /* COMMON */;
      case "Map":
      case "Set":
      case "WeakMap":
      case "WeakSet":
        return 2 /* COLLECTION */;
      default:
        return 0 /* INVALID */;
    }
  }

targetTypeMap 函数根据传入的 rawType 返回一个类型标识。ObjectArray 返回 1MapSetWeakMapWeakSet 返回 2,其他类型返回 0

  function getTargetType(value) {
    return value["__v_skip"] || !Object.isExtensible(value) ? 0 /* INVALID */ : targetTypeMap(toRawType(value));
  }

getTargetType 函数根据对象的 __v_skip 属性和可扩展性来确定对象的类型。如果 __v_skiptrue 或对象不可扩展,返回 0;否则,调用 targetTypeMap 获取类型。

  function reactive(target) {
    if (isReadonly(target)) {
      return target;
    }
    return createReactiveObject(
      target,
      false,
      mutableHandlers,
      mutableCollectionHandlers,
      reactiveMap
    );
  }

reactive 函数用于创建一个响应式对象。如果目标对象是只读的,直接返回目标对象。否则,调用 createReactiveObject 创建响应式对象。

  function shallowReactive(target) {
    return createReactiveObject(
      target,
      false,
      shallowReactiveHandlers,
      shallowCollectionHandlers,
      shallowReactiveMap
    );
  }

shallowReactive 函数用于创建一个浅层响应式对象。调用 createReactiveObject,传入浅层处理器和浅层响应式映射。

  function readonly(target) {
    return createReactiveObject(
      target,
      true,
      readonlyHandlers,
      readonlyCollectionHandlers,
      readonlyMap
    );
  }

readonly 函数用于创建一个只读对象。调用 createReactiveObject,传入只读处理器和只读映射。

  function shallowReadonly(target) {
    return createReactiveObject(
      target,
      true,
      shallowReadonlyHandlers,
      shallowReadonlyCollectionHandlers,
      shallowReadonlyMap
    );
  }

shallowReadonly 函数用于创建一个浅层只读对象。调用 createReactiveObject,传入浅层只读处理器和浅层只读映射。

这段代码的主要作用是定义了 Vue 3 中响应式系统的核心逻辑,包括创建响应式对象、浅层响应式对象、只读对象和浅层只读对象的函数,以及相关的处理器和映射。

function createReactiveObject(target, isReadonly2, baseHandlers, collectionHandlers, proxyMap) {
  if (!isObject(target)) {
    {
      warn(`value cannot be made reactive: ${String(target)}`);
    }
    return target;
  }
  if (target["__v_raw"] && !(isReadonly2 && target["__v_isReactive"])) {
    return target;
  }
  const existingProxy = proxyMap.get(target);
  if (existingProxy) {
    return existingProxy;
  }
  const targetType = getTargetType(target);
  if (targetType === 0 /* INVALID */) {
    return target;
  }
  const proxy = new Proxy(
    target,
    targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers
  );
  proxyMap.set(target, proxy);
  return proxy;
}
  1. createReactiveObject 函数用于创建一个响应式对象。
  2. if (!isObject(target)) 检查目标是否为对象,如果不是,发出警告并返回目标。
  3. if (target["__v_raw"] && !(isReadonly2 && target["__v_isReactive"])) 检查目标是否已经是一个原始对象,如果是且不是只读的,直接返回目标。
  4. const existingProxy = proxyMap.get(target); 检查目标是否已经有代理,如果有,返回现有的代理。
  5. const targetType = getTargetType(target); 获取目标的类型,如果是无效类型,返回目标。
  6. const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers); 创建一个新的代理对象,并根据目标类型选择处理程序。
  7. proxyMap.set(target, proxy); 将新创建的代理对象存储在 proxyMap 中。
  8. return proxy; 返回代理对象。
function isReactive(value) {
  if (isReadonly(value)) {
    return isReactive(value["__v_raw"]);
  }
  return !!(value && value["__v_isReactive"]);
}
  1. isReactive 函数用于检查一个值是否是响应式的。
  2. if (isReadonly(value)) 如果值是只读的,递归检查其原始值是否是响应式的。
  3. return !!(value && value["__v_isReactive"]); 返回一个布尔值,表示值是否是响应式的。
function isReadonly(value) {
  return !!(value && value["__v_isReadonly"]);
}
  1. isReadonly 函数用于检查一个值是否是只读的。
  2. return !!(value && value["__v_isReadonly"]); 返回一个布尔值,表示值是否是只读的。
function isShallow(value) {
  return !!(value && value["__v_isShallow"]);
}
  1. isShallow 函数用于检查一个值是否是浅层响应式的。
  2. return !!(value && value["__v_isShallow"]); 返回一个布尔值,表示值是否是浅层响应式的。
function isProxy(value) {
  return isReactive(value) || isReadonly(value);
}
  1. isProxy 函数用于检查一个值是否是代理对象。
  2. return isReactive(value) || isReadonly(value); 返回一个布尔值,表示值是否是响应式或只读的。
function toRaw(observed) {
  const raw = observed && observed["__v_raw"];
  return raw ? toRaw(raw) : observed;
}
  1. toRaw 函数用于获取一个代理对象的原始对象。
  2. const raw = observed && observed["__v_raw"]; 获取代理对象的原始对象。
  3. return raw ? toRaw(raw) : observed; 如果存在原始对象,递归获取其原始对象,否则返回观察对象。
function markRaw(value) {
  if (Object.isExtensible(value)) {
    def(value, "__v_skip", true);
  }
  return value;
}
  1. markRaw 函数用于标记一个对象为原始对象,使其不被 Vue 的响应式系统处理。
  2. if (Object.isExtensible(value)) 检查对象是否可扩展,如果是,定义一个 __v_skip 属性为 true
  3. return value; 返回标记后的对象。
const toReactive = (value) => isObject(value) ? reactive(value) : value;
const toReadonly = (value) => isObject(value) ? readonly(value) : value;
  1. toReactive 函数用于将一个对象转换为响应式对象。
  2. toReadonly 函数用于将一个对象转换为只读对象。
const COMPUTED_SIDE_EFFECT_WARN = `Computed is still dirty after getter evaluation, likely because a computed is mutating its own dependency in its getter. State mutations in computed getters should be avoided.  Check the docs for more details: https://vuejs.org/guide/essentials/computed.html#getters-should-be-side-effect-free`;
class ComputedRefImpl {
  constructor(getter, _setter, isReadonly, isSSR) {
    this.getter = getter;
    this._setter = _setter;
    this.dep = void 0;
    this.__v_isRef = true;
    this["__v_isReadonly"] = false;
    this.effect = new ReactiveEffect(
      () => getter(this._value),
      () => triggerRefValue(
        this,
        this.effect._dirtyLevel === 2 ? 2 : 3
      )
    );
    this.effect.computed = this;
    this.effect.active = this._cacheable = !isSSR;
    this["__v_isReadonly"] = isReadonly;
  }
  get value() {
    const self = toRaw(this);
    if ((!self._cacheable || self.effect.dirty) && hasChanged(self._value, self._value = self.effect.run())) {
      triggerRefValue(self, 4);
    }
    trackRefValue(self);
    if (self.effect._dirtyLevel >= 2) {
      if (this._warnRecursive) {
        warn(COMPUTED_SIDE_EFFECT_WARN, `

getter: `, this.getter);
      }
      triggerRefValue(self, 2);
    }
    return self._value;
  }
  set value(newValue) {
    this._setter(newValue);
  }
  // #region polyfill _dirty for backward compatibility third party code for Vue <= 3.3.x
  get _dirty() {
    return this.effect.dirty;
  }
  set _dirty(v) {
    this.effect.dirty = v;
  }
  // #endregion
}
  1. COMPUTED_SIDE_EFFECT_WARN 是一个警告信息,提示计算属性的 getter 中不应有副作用。
  2. ComputedRefImpl 类实现了计算属性的逻辑。
  3. constructor 构造函数初始化计算属性的 getter、setter、依赖、响应式效果等。
  4. get value() 获取计算属性的值,处理缓存和依赖追踪。
  5. set value(newValue) 设置计算属性的值,通过 setter 更新。
  6. get _dirty()set _dirty(v) 是为了向后兼容 Vue 3.3.x 及以下版本的第三方代码。
function computed(getterOrOptions, debugOptions, isSSR = false) {
  let getter;
  let setter;
  const onlyGetter = isFunction(getterOrOptions);
  if (onlyGetter) {
    getter = getterOrOptions;
    setter = () => {
      warn("Write operation failed: computed value is readonly");
    };
  } else {
    getter = getterOrOptions.get;
    setter = getterOrOptions.set;
  }
  const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);
  if (debugOptions && !isSSR) {
    cRef.effect.onTrack = debugOptions.onTrack;
    cRef.effect.onTrigger = debugOptions.onTrigger;
  }
  return cRef;
}

解释:

  1. 函数声明computed 函数用于创建一个计算属性。
  2. 参数
    • getterOrOptions:可以是一个函数(getter)或一个包含 getset 方法的对象。
    • debugOptions:调试选项。
    • isSSR:是否在服务器端渲染中使用。
  3. 变量声明
    • gettersetter:分别用于存储 getter 和 setter。
    • onlyGetter:判断 getterOrOptions 是否是一个函数。
  4. 条件判断
    • 如果 getterOrOptions 是函数,则 getter 赋值为 getterOrOptionssetter 赋值为一个警告函数。
    • 否则,gettersetter 分别从 getterOrOptions 对象中获取。
  5. 创建 ComputedRefImpl 实例cRef 是一个 ComputedRefImpl 实例,传入 gettersetteronlyGetter!setter 以及 isSSR
  6. 调试选项:如果有 debugOptions 且不是 SSR 环境,设置 cRef.effectonTrackonTrigger
  7. 返回 cRef:返回计算属性引用。
function trackRefValue(ref2) {
  var _a;
  if (shouldTrack && activeEffect) {
    ref2 = toRaw(ref2);
    trackEffect(
      activeEffect,
      (_a = ref2.dep) != null ? _a : ref2.dep = createDep(
        () => ref2.dep = void 0,
        ref2 instanceof ComputedRefImpl ? ref2 : void 0
      ),
      {
        target: ref2,
        type: "get",
        key: "value"
      }
    );
  }
}

解释:

  1. 函数声明trackRefValue 用于追踪引用值的依赖。
  2. 参数ref2 是一个引用对象。
  3. 条件判断
    • 如果 shouldTrackactiveEffect 为真,执行追踪逻辑。
  4. 转换为原始值ref2 被转换为原始值。
  5. 追踪依赖:调用 trackEffect,传入 activeEffect、依赖集合 dep 以及追踪信息对象。
function triggerRefValue(ref2, dirtyLevel = 4, newVal) {
  ref2 = toRaw(ref2);
  const dep = ref2.dep;
  if (dep) {
    triggerEffects(
      dep,
      dirtyLevel,
      {
        target: ref2,
        type: "set",
        key: "value",
        newValue: newVal
      }
    );
  }
}

解释:

  1. 函数声明triggerRefValue 用于触发引用值的依赖更新。
  2. 参数
    • ref2:引用对象。
    • dirtyLevel:脏值级别,默认为 4。
    • newVal:新值。
  3. 转换为原始值ref2 被转换为原始值。
  4. 获取依赖集合dep 是引用对象的依赖集合。
  5. 触发依赖更新:如果 dep 存在,调用 triggerEffects,传入 depdirtyLevel 以及更新信息对象。
function isRef(r) {
  return !!(r && r.__v_isRef === true);
}

解释:

  1. 函数声明isRef 用于判断一个对象是否是引用。
  2. 参数r 是待判断的对象。
  3. 返回值:如果 r 存在且 __v_isRef 属性为 true,返回 true,否则返回 false
function ref(value) {
  return createRef(value, false);
}

解释:

  1. 函数声明ref 用于创建一个普通引用。
  2. 参数value 是引用的初始值。
  3. 返回值:调用 createRef,传入 valuefalse,返回一个新的引用对象。
function shallowRef(value) {
  return createRef(value, true);
}

解释:

  1. 函数声明shallowRef 用于创建一个浅引用。
  2. 参数value 是引用的初始值。
  3. 返回值:调用 createRef,传入 valuetrue,返回一个新的浅引用对象。
function createRef(rawValue, shallow) {
  if (isRef(rawValue)) {
    return rawValue;
  }
  return new RefImpl(rawValue, shallow);
}

解释:

  1. 函数声明createRef 用于创建一个引用对象。
  2. 参数
    • rawValue:引用的初始值。
    • shallow:是否为浅引用。
  3. 条件判断:如果 rawValue 已经是引用,直接返回。
  4. 返回值:创建并返回一个新的 RefImpl 实例。
class RefImpl {
  constructor(value, __v_isShallow) {
    this.__v_isShallow = __v_isShallow;
    this.dep = void 0;
    this.__v_isRef = true;
    this._rawValue = __v_isShallow ? value : toRaw(value);
    this._value = __v_isShallow ? value : toReactive(value);
  }
  get value() {
    trackRefValue(this);
    return this._value;
  }
  set value(newVal) {
    const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal);
    newVal = useDirectValue ? newVal : toRaw(newVal);
    if (hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal;
      this._value = useDirectValue ? newVal : toReactive(newVal);
      triggerRefValue(this, 4, newVal);
    }
  }
}

解释:

  1. 类声明RefImpl 是引用的实现类。
  2. 构造函数
    • value:初始值。
    • __v_isShallow:是否为浅引用。
  3. 属性初始化
    • __v_isShallow:是否为浅引用。
    • dep:依赖集合,初始为 undefined
    • __v_isRef:标记为引用。
    • _rawValue:原始值,如果是浅引用则为 value,否则转换为原始值。
    • _value:实际值,如果是浅引用则为 value,否则转换为响应式对象。
  4. gettervalue 获取引用的值,并追踪依赖。
  5. settervalue 设置引用的新值,并触发依赖更新。
function triggerRef(ref2) {
  triggerRefValue(ref2, 4, ref2.value);
}

解释:

  1. 函数声明triggerRef 用于手动触发引用的依赖更新。
  2. 参数ref2 是引用对象。
  3. 调用 triggerRefValue:传入 ref2、脏值级别 4ref2.value,触发依赖更新。
function unref(ref2) {
  return isRef(ref2) ? ref2.value : ref2;
}

解释:

  1. 函数声明unref 用于获取引用的值。
  2. 参数ref2 是引用对象。
  3. 返回值:如果 ref2 是引用,返回其值,否则返回 ref2 本身。
function toValue(source) {
  return isFunction(source) ? source() : unref(source);
}

解释:

  1. 函数声明toValue 用于获取源对象的值。
  2. 参数source 是源对象。
  3. 返回值:如果 source 是函数,调用并返回其结果,否则调用 unref 获取其值。
const shallowUnwrapHandlers = {
  get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)),
  set: (target, key, value, receiver) => {
    const oldValue = target[key];
    if (isRef(oldValue) && !isRef(value)) {
      oldValue.value = value;
      return true;
    } else {
      return Reflect.set(target, key, value, receiver);
    }
  }
};

解释:

  1. 常量声明shallowUnwrapHandlers 是一个处理器对象,用于浅解包引用。
  2. get 方法:获取属性值时,调用 unref 获取实际值。
  3. set 方法:设置属性值时,如果旧值是引用且新值不是引用,直接设置旧值的 value,否则使用 Reflect.set 设置新值。
function proxyRefs(objectWithRefs) {
  return isReactive(objectWithRefs) ? objectWithRefs : new Proxy(objectWithRefs, shallowUnwrapHandlers);
}

解释:

  1. 函数声明proxyRefs 用于代理包含引用的对象。
  2. 参数objectWithRefs 是包含引用的对象。
  3. 返回值:如果 objectWithRefs 是响应式对象,直接返回,否则返回一个新的代理对象,使用 shallowUnwrapHandlers 处理器。
class CustomRefImpl {
  constructor(factory) {
    this.dep = void 0;
    this.__v_isRef = true;
    const { get, set } = factory(
      () => trackRefValue(this),
      () => triggerRefValue(this)
    );
    this._get = get;
    this._set = set;
  }
  get value() {
    return this._get();
  }
  set value(newVal) {
    this._set(newVal);
  }
}

解释:

  1. 类声明CustomRefImpl 是自定义引用的实现类。
  2. 构造函数
    • factory:工厂函数,返回 getset 方法。
  3. 属性初始化
    • dep:依赖集合,初始为 undefined
    • __v_isRef:标记为引用。
    • _get_set:分别从 factory 中获取 getset 方法。
  4. gettervalue 获取引用的值,调用 _get 方法。
  5. settervalue 设置引用的新值,调用 _set 方法。
function customRef(factory) {
  return new CustomRefImpl(factory);
}

解释:

  1. 函数声明customRef 用于创建一个自定义引用。
  2. 参数factory 是工厂函数。
  3. 返回值:创建并返回一个新的 CustomRefImpl 实例。
function toRefs(object) {
  if (!isProxy(object)) {
    warn(`toRefs() expects a reactive object but received a plain one.`);
  }
  const ret = isArray(object) ? new Array(object.length) : {};
  for (const key in object) {
    ret[key] = propertyToRef(object, key);
  }
  return ret;
}

解释:

  1. 函数声明toRefs 用于将对象的属性转换为引用。
  2. 参数object 是待转换的对象。
  3. 条件判断:如果 object 不是代理对象,发出警告。
  4. 返回值
    • 如果 object 是数组,创建一个相同长度的新数组。
    • 否则,创建一个新的空对象。
  5. 遍历属性:遍历 object 的属性,将每个属性转换为引用并赋值给 ret
  6. 返回 ret:返回包含引用的对象。
class ObjectRefImpl {
  constructor(_object, _key, _defaultValue) {
    this._object = _object;
    this._key = _key;
    this._defaultValue = _defaultValue;
    this.__v_isRef = true;
  }
  get value() {
    const val = this._object[this._key];
    return val === void 0 ? this._defaultValue : val;
  }
  set value(newVal) {
    this._object[this._key] = newVal;
  }
  get dep() {
    return getDepFromReactive(toRaw(this._object), this._key);
  }
}

解释:

  1. 类声明ObjectRefImpl 是对象属性引用的实现类。
  2. 构造函数
    • _object:对象。
    • _key:属性键。
    • _defaultValue:默认值。
  3. 属性初始化
    • _object_key_defaultValue:分别存储对象、属性键和默认值。
    • __v_isRef:标记为引用。
  4. gettervalue 获取属性值,如果属性值为 undefined,返回默认值。
  5. settervalue 设置属性的新值。
  6. getterdep 获取属性的依赖集合。
class GetterRefImpl {
  constructor(_getter) {
    this._getter = _getter;
    this.__v_isRef = true;
    this.__v_isReadonly = true;
  }
  get value() {
    return this._getter();
  }
}

解释:

  1. 类声明GetterRefImpl 是 getter 引用的实现类。
  2. 构造函数
    • _getter:getter 函数。
  3. 属性初始化
    • _getter:存储 getter 函数。
    • __v_isRef:标记为引用。
    • __v_isReadonly:标记为只读引用。
  4. gettervalue 获取引用的值,调用 _getter 方法。
function toRef(source, key, defaultValue) {
  if (isRef(source)) {
    return source;
  } else if (isFunction(source)) {
    return new GetterRefImpl(source);
  } else if (isObject(source) && arguments.length > 1) {
    return propertyToRef(source, key, defaultValue);
  } else {
    return ref(source);
  }
}

解释:

  1. 函数声明toRef 用于将源对象转换为引用。
  2. 参数
    • source:源对象。
    • key:属性键。
    • defaultValue:默认值。
  3. 条件判断
    • 如果 source 是引用,直接返回。
    • 如果 source 是函数,返回一个新的 GetterRefImpl 实例。
    • 如果 source 是对象且有多个参数,调用 propertyToRef,返回属性引用。
    • 否则,调用 ref,返回一个新的引用对象。
function propertyToRef(source, key, defaultValue) {
  const val = source[key];
  return isRef(val) ? val : new ObjectRefImpl(source, key, defaultValue);
}

解释:

  1. 函数声明propertyToRef 用于将对象的属性转换为引用。
  2. 参数
    • source
换为引用。
2. **参数**:
   - `source`:源对象。
   - `key`:属性键。
   - `defaultValue`:默认值。
3. **获取属性值**:`val` 是 `source` 对象中 `key` 属性的值。
4. **返回值**:如果 `val` 是引用,直接返回;否则,返回一个新的 `ObjectRefImpl` 实例。

const deferredComputed = computed;

解释:

  1. 常量声明deferredComputedcomputed 函数的别名,用于创建延迟计算属性。
const TrackOpTypes = {
  "GET": "get",
  "HAS": "has",
  "ITERATE": "iterate"
};

解释:

  1. 常量声明TrackOpTypes 是一个对象,包含三种操作类型:
    • GET:获取操作。
    • HAS:检查属性是否存在。
    • ITERATE:迭代操作。
const TriggerOpTypes = {
  "SET": "set",
  "ADD": "add",
  "DELETE": "delete",
  "CLEAR": "clear"
};

解释:

  1. 常量声明TriggerOpTypes 是一个对象,包含四种触发操作类型:
    • SET:设置操作。
    • ADD:添加操作。
    • DELETE:删除操作。
    • CLEAR:清除操作。
const ReactiveFlags = {
  "SKIP": "__v_skip",
  "IS_REACTIVE": "__v_isReactive",
  "IS_READONLY": "__v_isReadonly",
  "IS_SHALLOW": "__v_isShallow",
  "RAW": "__v_raw"
};

解释:

  1. 常量声明ReactiveFlags 是一个对象,包含五个标志属性:
    • SKIP:跳过反应性处理。
    • IS_REACTIVE:标记为响应式对象。
    • IS_READONLY:标记为只读对象。
    • IS_SHALLOW:标记为浅响应式对象。
    • RAW:获取原始对象。

这些代码片段主要涉及 Vue 3 中响应式系统的实现,包括计算属性、引用、依赖追踪和触发等功能。通过这些实现,Vue 3 能够高效地管理和更新组件的状态。