概览
基础对象的代理指的是对基础对象进行代理,使基础对象的属性可以被响应式地访问和修改。该实现具体参见
packages\reactivity\src\baseHandlers.ts
本文主要介绍如下四类基础对象的代理方法:
mutableHandlers:可读写代理readonlyHandlers:只读代理shallowReactiveHandlers:浅响应式代理shallowReadonlyHandlers:浅只读代理
源码分析
实际上上述四类代理方法只是实例化了两个类MutableReactiveHandler和ReadonlyReactiveHandler
            
            
              js
              
              
            
          
          const mutableHandlers = /* @__PURE__ */ new MutableReactiveHandler();
const readonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler();
const shallowReactiveHandlers = /* @__PURE__ */ new MutableReactiveHandler(true);
const shallowReadonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler(true);
        而MutableReactiveHandler和ReadonlyReactiveHandler都是继承于BaseReactiveHandler类的,BaseReactiveHandler类的主要功能是定义基础的代理方法,而MutableReactiveHandler和ReadonlyReactiveHandler类则是在基础的代理方法上进行了扩展,添加了可读写和只读的功能。
BaseReactiveHandler类
BaseReactiveHandler类的实现如下:
            
            
              js
              
              
            
          
          function hasOwnProperty(key) {
  if (!isSymbol(key)) key = String(key);
  const obj = toRaw(this);
  // 依赖收集
  track(obj, "has", key);
  return obj.hasOwnProperty(key);
}
class BaseReactiveHandler {
  constructor(_isReadonly = false, _isShallow = false) {
    this._isReadonly = _isReadonly;
    this._isShallow = _isShallow;
  }
  get(target, key, receiver) {
    if (key === "__v_skip") return target["__v_skip"];
    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) || // receiver is not the reactive proxy, but has the same prototype
      // this means the reciever is a user proxy of the reactive proxy
      Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)) {
        return target;
      }
      return;
    }
    const targetIsArray = isArray(target);
    if (!isReadonly2) {
      let fn;
      if (targetIsArray && (fn = arrayInstrumentations[key])) {
        return fn;
      }
      if (key === "hasOwnProperty") {
        return hasOwnProperty;
      }
    }
    const res = Reflect.get(target, key, isRef(target) ? target : 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;
  }
}
        BaseReactiveHandler类只是定义了get()方法,当读取代理对象时,会触发get()方法进行拦截,在非只读的情况下,会调用track方法进行依赖收集。如下是BaseReactiveHandler类的实现过程分析:
- 类的构造器接收两个参数:
_isReadonly和_isShallow,分别表示是否只读和是否是浅层响应式. get()方法接收三个参数:target目标对象、key属性名、receiver代理对象。当get()方法被触发时,若key是__v_isReactive、__v_isShallow或者__v_raw,则根据实例的_isReadonly或者_isShallow返回对应的布尔值.- 若
key是__v_raw,则根据_isReadonly和_isShallow确定代理对象的缓存(即调用createReactiveObject中的proxyMap缓存变量),然后比较receiver是否是缓存中的代理对象,如果是,则返回目标对象target;若不是,则判断target和receiver的原型是否相等,若相等,则返回目标对象target.如果二者皆不相等,则什么也不返回. - 若
key不是上述属性,则判断target是否是数组。如果是可写的,且target是数组,key又是数组的属性,那么就返回数组的方法。若key是hasOwnProperty,则返回自定义的hasOwnProperty方法,该方法的实现如上,该方法的作用是判断target是否有key属性,并且调用track进行依赖收集. - 调用
Reflect.get(target, key, receiver)方法获取target上key的值res. - 判断
key是不是内置的Symbol属性或一些普通属性__proto__,__v_isRef,__isVue,若是,则直接返回res,避免对这些属性进行依赖收集. - 判断是否只读,若不是只读,则调用
track进行依赖收集. - 判断是否是浅层响应式,若是,则直接返回
res,避免对res进行递归代理. - 判断
res是否是Ref对象,若是,则继续判断,若target是数组且key是整数索引,则返回res;否则返回res.value. - 若
res是对象,则判断是否只读,若不是只读,则递归调用reactive进行代理,否则递归调用readonly进行代理. - 最后返回
res. 
MutableReactiveHandler类
MutableReactiveHandler的实现如下:
            
            
              js
              
              
            
          
          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;
  }
  deleteProperty(target, key) {
    const hadKey = hasOwn(target, key);
    const oldValue = target[key];
    const result = Reflect.deleteProperty(target, key);
    if (result && hadKey) {
      trigger(target, "delete", key, void 0, oldValue);
    }
    return result;
  }
  has(target, key) {
    const result = Reflect.has(target, key);
    if (!isSymbol(key) || !builtInSymbols.has(key)) {
      track(target, "has", key);
    }
    return result;
  }
  ownKeys(target) {
    track(
      target,
      "iterate",
      isArray(target) ? "length" : ITERATE_KEY
    );
    return Reflect.ownKeys(target);
  }
}
        MutableReactiveHandler类继承于BaseReactiveHandler类,在其内部定义了set、deleteProperty、has、ownKeys方法四个方法。在它的构造函数中,接受一个参数isShallow2表示是否是浅层响应,默认为false,然后调用super,响应式对象肯定不是只读的,所以super第一个参数是false。如下分析MutableReactiveHandler的四个方法。
set
当target目标对象上的值发生改变,或者说是对target进行写操作时,会调用set方法。
set方法接收四个参数:target目标对象、key属性名、value属性值、receiver代理对象。
- 首先获取
target的旧值oldValue,判断是否是浅层代理,若不是,则继续判断新值,若新值是深层响应式,则分别调用toRaw获取新值和旧值的原始值;然后判断,若target是对象,且旧值是Ref对象而新值不是Ref对象,若旧值是只读的,则返回false;否则将旧值的value属性赋值为新值,返回true. - 若
target不是数组,且key是整数索引且key的长度小于target数组的长度,则说明是在更新target[key]的值;若target不是数组,则调用自定义方法hasOwn(实际就是Object.prototype.hasOwnProperty)判断target是否有key属性.
hadKey用于表示是更新还是新增操作,true则更新/false则新增. - 调用
Reflect.set设置target的key为value,返回结果保存至变量result。 - 判断
target和receiver的原始对象是否相等,只有相等才触发副作用。这个检查是为了避免在原型链上的属性设置时错误地触发副作用。然后判断hadKey,若hadKey为true,则说明是更新操作,会先调用hasChanged判断新旧值是否相等,若不等,则调用trigger触发更新副作用;若hadKey为false,则说明是新增操作,调用trigger触发新增副作用. - 最后返回
result 
deleteProperty
deleteProperty方法在删除target上的某属性时会被触发。
deleteProperty方法接收两个参数:target目标对象、key属性名。
- 调用
hasOwn判断target是否有key属性,判断结果记为hadKey,获取旧值oldValue。 - 调用
Reflect.deleteProperty删除target的key属性,返回结果保存至变量result。 - 判断
result与hadKey都为true,则调用trigger触发删除副作用。 - 最后返回
result 
has
has方法会拦截in操作符。如下是它的处理流程:
- 调用
Reflect.has判断target是否有key属性,记为result - 判断
key是否是Symbol类型或者key是否是内置的Symbol,若不是,则调用track进行依赖收集. - 最后返回属性检测的结果
result 
ownKeys
ownKeys方法会拦截Object.keys、Object.getOwnPropertyNames、Object.getOwnPropertySymbols、for...in循环。如下是它的处理流程:
- 调用
track进行依赖收集。若target是数组,则跟踪length属性的变化;若target不是数组,则跟踪Symbol(iterator)。这样当对对象的属性添加、删除或数组长度变化时,就会触发相关的副作用函数。 - 最后返回目标对象的所有自有属性键
 
ReadonlyReactiveHandler类
ReadonlyReactiveHandler类就更简单了,因为通过该类实例化的处理器方法都是针对只读对象的,所以它的set、deleteProperty方法都直接返回true,并在warn中提示目标对象是只读的。
ReadonlyReactiveHandler的实现如下:
            
            
              js
              
              
            
          
          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;
  }
  deleteProperty(target, key) {
    {
      warn(
        `Delete operation on key "${String(key)}" failed: target is readonly.`,
        target
      );
    }
    return true;
  }
}