响应式基础 API(reactive.ts) 
源码调试方法
node版本要大于 16,装依赖- 执行
dev命令,比如yarn dev- 页面中引用
dist/vue.global.js即可源码本身也有一些
examples html,比如packages/vue/examples/composition/commits.html
createReactiveObject 
创建响应式对象的方法,非常重要
baseHandlers和collectionHandlers是调用对应的方法时就确定好的,就是reactive、readonly...
proxyMap也是调用对应的方法时就确定好的,而proxyMap对应的是以下 4 种tsexport const reactiveMap = new WeakMap<Target, any>(); export const shallowReactiveMap = new WeakMap<Target, any>(); export const readonlyMap = new WeakMap<Target, any>(); export const shallowReadonlyMap = new WeakMap<Target, any>();
function createReactiveObject(
  target: Target,
  isReadonly: boolean,
  baseHandlers: ProxyHandler<any>,
  collectionHandlers: ProxyHandler<any>,
  proxyMap: WeakMap<Target, any>
) {
  // 如果target的类型不属于Object, Array, Map, Set, WeakMap, WeakSet其中的一个,则直接返回
  if (!isObject(target)) {
    if (__DEV__) {
      console.warn(`value cannot be made reactive: ${String(target)}`);
    }
    return target;
  }
  // 如果target已经是一个由本方法创建的proxy了,直接返回
  // 例外: 调用readonly创建reactive对象的只读副本 e.g. readonly(reactive({}))
  if (
    target[ReactiveFlags.RAW] &&
    !(isReadonly && target[ReactiveFlags.IS_REACTIVE])
  ) {
    return target;
  }
  // 在对应的缓存列表(WeakMap)中寻找对应的Proxy
  const existingProxy = proxyMap.get(target);
  if (existingProxy) {
    return existingProxy;
  }
  // only a whitelist of value types can be observed.
  const targetType = getTargetType(target);
  // 判断target的类型是否符合要求,TargetType.INVALID代表target不能扩展或者被标记了不能转换为响应式对象(markRaw)
  if (targetType === TargetType.INVALID) {
    return target;
  }
  const proxy = new Proxy(
    target,
    // Map, Set, WeakMap, WeakSet使用collectionHandlers
    // Object, Array使用baseHandlers
    targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
  );
  // 缓存起来
  proxyMap.set(target, proxy);
  return proxy;
}有了createReactiveObject,下面 4 中创建响应式对象的方法,只要传对应的参数即可
reactive 
创建响应式对象并返回副本,响应式转换是“深层”的
如果任何
property使用了ref,当它通过代理访问时,则被自动解包如果传入的
target是一个readonly代理,则直接返回target
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>;
export function reactive(target: object) {
  // if trying to observe a readonly proxy, return the readonly version.
  // 如果尝试观察只读代理,返回只读版本。
  if (isReadonly(target)) {
    return target;
  }
  return createReactiveObject(
    target,
    false, // 不是只读
    mutableHandlers, // 对应的baseHandlers
    mutableCollectionHandlers, // 对应的collectionHandlers
    reactiveMap // 对应的proxyMap
  );
}readonly 
接受一个对象 (响应式或纯对象) 或 ref 并返回原始对象的只读代理。只读代理是深层的:任何被访问的嵌套
property也是只读的。如果任何 property 使用了
ref,当它通过代理访问时,则被自动解包
export function readonly<T extends object>(
  target: T
): DeepReadonly<UnwrapNestedRefs<T>> {
  return createReactiveObject(
    target,
    true,
    readonlyHandlers,
    readonlyCollectionHandlers,
    readonlyMap
  );
}shallowReactive 
返回浅层的响应式对象副本,只有根级别属性是响应的,不会自动展开
ref(即使是根属性的ref)
export function shallowReactive<T extends object>(
  target: T
): ShallowReactive<T> {
  return createReactiveObject(
    target,
    false,
    shallowReactiveHandlers,
    shallowCollectionHandlers,
    shallowReactiveMap
  );
}shallowReadonly 
返回浅层的响应式对象只读副本,只有根级别属性是响应的,不会自动展开
ref(即使是根属性的ref)
export function shallowReadonly<T extends object>(target: T): Readonly<T> {
  return createReactiveObject(
    target,
    true,
    shallowReadonlyHandlers,
    shallowReadonlyCollectionHandlers,
    shallowReadonlyMap
  );
}小结 
- 都是由 - createReactiveObject创建的代理
- reactive、- readonly会进行深层的转换,在- get的时候将解包所有深层的 refs,同时维持- ref的响应性。
- shallowReactive、- shallowReadonly会进行浅层的转换(即根对象),任何使用- ref的 property 都不会被代理自动解包
ReactiveFlags 
从名字就可以看出,这些属性用于判断
响应式对象的一些标识
export const enum ReactiveFlags {
  // 跳过标识
  SKIP = "__v_skip",
  // 是否为(reactive / shallowReactive)创建的响应式对象
  IS_REACTIVE = "__v_isReactive",
  // 是否为只读响应式代理(readonly / shallowReadonly)
  IS_READONLY = "__v_isReadonly",
  // 是否为浅层代理
  IS_SHALLOW = "__v_isShallow",
  // 原始对象
  RAW = "__v_raw",
}
export interface Target {
  [ReactiveFlags.SKIP]?: boolean;
  [ReactiveFlags.IS_REACTIVE]?: boolean;
  [ReactiveFlags.IS_READONLY]?: boolean;
  [ReactiveFlags.IS_SHALLOW]?: boolean;
  [ReactiveFlags.RAW]?: any;
}IS_REACTIVE 
TIP
其中ReactiveFlags.IS_REACTIVE比较特殊,他的值取决于target的isReadonly。isReadonly是在创建proxy的时候就确定好的(具体的实现是在proxy的handler中)
拿
baseHandlers.ts举例
const get = /*#__PURE__*/ createGetter();
const shallowGet = /*#__PURE__*/ createGetter(false, true);
const readonlyGet = /*#__PURE__*/ createGetter(true);
const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true);reactive、readonly、shallowReactive、shallowReadonly都是创建响应式对象(代理),因此IS_REACTIVE只需判断只读的标识即可
function createGetter(isReadonly = false, shallow = false) {
  return function get(target: Target, key: string | symbol, receiver: object) {
    if (key === ReactiveFlags.IS_REACTIVE) {
      return !isReadonly;
    } else if (key === ReactiveFlags.IS_READONLY) {
      return isReadonly;
    } else if (key === ReactiveFlags.IS_SHALLOW) {
      return shallow;
    } else if (
      key === ReactiveFlags.RAW &&
      receiver ===
        (isReadonly
          ? shallow
            ? shallowReadonlyMap
            : readonlyMap
          : shallow
          ? shallowReactiveMap
          : reactiveMap
        ).get(target)
    ) {
      return target;
    }
    // ...
  };
}isReactive 
检查对象是否是由
reactive创建的响应式代理。从源码可以看出,如果是
readonly创建的value,会进行递归判断,也就是说
export function isReactive(value: unknown): boolean {
  if (isReadonly(value)) {
    return isReactive((value as Target)[ReactiveFlags.RAW]);
  }
  return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE]);
}isReadonly 
检查对象是否是由
readonly创建的只读代理。他的工作就是检查
ReactiveFlags.IS_READONLY标识
export function isReadonly(value: unknown): boolean {
  return !!(value && (value as Target)[ReactiveFlags.IS_READONLY]);
}isShallow 
v3.2.28 (2022-01-21)+,但本文记录时,官网文档没有说明该方法,算是彩蛋了检查对象是否为浅层的代理
他的工作就是检查
ReactiveFlags.IS_SHALLOW标识
export function isShallow(value: unknown): boolean {
  return !!(value && (value as Target)[ReactiveFlags.IS_SHALLOW]);
}isProxy 
检查对象是否是由
reactive或readonly创建的 proxy。所以他的判断交给了
isReactive和isReadonly
export function isProxy(value: unknown): boolean {
  return isReactive(value) || isReadonly(value);
}toRaw 
- 先拿到 observed 的(ReactiveFlags.RAW)值 
- 如果 raw 没有值(undefined),则证明 observed 是普通对象,直接返回 observed 
- 如果 raw 有值,那么会存在两种情况 - observed 的代理只有一层
- observed 是一个嵌套多层的响应式对象,比如:readonly(reactive({}))、readonly(readonly({}))
 
- 所以需要递归判断 
- 重点结束条件:如果 raw 的值是 undefined 就是拿到原始对象了 
export function toRaw<T>(observed: T): T {
  const raw = observed && (observed as Target)[ReactiveFlags.RAW];
  return raw ? toRaw(raw) : observed;
}markRaw 
标记一个对象不会被代理,加入黑名单,不会被
observed。目前来看似乎没有提供方法取消标记用
Object.defineProperty设置ReactiveFlags.SKIP属性为true在用
reactive创建响应式对象时,会调用getTargetType(target)进行判断,如果target的ReactiveFlags.SKIP属性是true,或者是不可扩展的,则认定这个target是无效的;因此并不会创建响应式对象
export function markRaw<T extends object>(value: T): T {
  def(value, ReactiveFlags.SKIP, true);
  return value;
}
function getTargetType(value: Target) {
  return value[ReactiveFlags.SKIP] || !Object.isExtensible(value)
    ? TargetType.INVALID
    : targetTypeMap(toRawType(value));
}
function createReactiveObject() {
  // ...
  // only a whitelist of value types can be observed.
  const targetType = getTargetType(target);
  if (targetType === TargetType.INVALID) {
    return target; // 返回原始对象
  }
  // ...
}例子
const obj: any = {
  name: "gauhar",
};
// obj被标记了
markRaw(obj);
// state不是响应的
const state = reactive(obj); // state === obj
function handleClick() {
  // 不会响应
  state.name = "1234";
  state.sex = "man";
}上面的state === obj,因为创建reactive的时候被拦截return target了。属性有被修改和新增,但已经不是响应式的了。
markRaw只劫持了一层(从源码可以看出),因此对面里的属性没有被标注。比如const obj: any = {
  name: "gauhar",
  info: {
    hair: "black",
  },
};
// obj被标注了,但info没有
markRaw(obj);
const state = reactive(obj);
// 这种情况下如果使用obj.info去创建reactive
const data = reactive(obj.info);
function handleClick() {
  // 不会响应(按照我们上面的说法,这里应该是不会响应的)
  state.name = "1234";
  state.sex = "man";
  // 但是由于`同一性风险`,会得到原始对象(obj)被代理后的版本;这个函数里的改变会被响应
  data.hair = "red"; // observed
}关于同一性风险具体可以参考官网 👊
两个内部方法 
都是进行对应的转换
export const toReactive = <T extends unknown>(value: T): T =>
  isObject(value) ? reactive(value) : value;
export const toReadonly = <T extends unknown>(value: T): T =>
  isObject(value) ? readonly(value as Record<any, any>) : value;