Skip to content

Vue(v3.0.11)源码简析之响应式(reactive,ref,computed)相关实现 #10

Open
@unproductive-wanyicheng

Description

@unproductive-wanyicheng

vue中的响应式主要是通过把目标对象变成代理对象,同时设置对应属性的handlers来控制的,我们看下实际vue中用到的handlers都是怎么实现的,以及ref对象和computed对象的实现:

// 不予track追踪的对象key
const isNonTrackableKeys = /*#__PURE__*/ makeMap(`__proto__,__v_isRef,__isVue`);
// Object.getOwnPropertyNames(Symbol): ["length", "name", "prototype", "for", "keyFor", "asyncIterator", "hasInstance", "isConcatSpreadable", "iterator", "match", "matchAll", "replace", "search", "species", "split", "toPrimitive", "toStringTag", "unscopables"]
// .map(key => Symbol[key]): 得到对应key的值
// .filter(isSymbol) 保留 Symbol 类型的值
// builtInSymbols 中的key 也同 isNonTrackableKeys 中的key一样 不予track追踪
const builtInSymbols = new Set(Object.getOwnPropertyNames(Symbol)
    .map(key => Symbol[key])
    .filter(isSymbol));
// proxy代理的拦截器handler的get实现
// 深度遍历追踪 每层都追踪当前属性
const get = /*#__PURE__*/ createGetter();
// 只代理一层 每层都追踪当前属性(只有一层)
const shallowGet = /*#__PURE__*/ createGetter(false, true);
// 深度遍历追踪 每层都不追踪当前属性
const readonlyGet = /*#__PURE__*/ createGetter(true);
// 只代理一层 每层都不追踪当前属性(其实只有一层)
const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true);
// 我们对数组对象的 'includes', 'indexOf', 'lastIndexOf' 'push', 'pop', 'shift', 'unshift', 'splice'
// 上述几个方法做了拦截处理 用户在调用数组实例的原生方法的时候 其实是调用了我们的方法 在原生方法的基础上加了额外的控制逻辑
const arrayInstrumentations = {};
['includes', 'indexOf', 'lastIndexOf'].forEach(key => {
    // 原生方法函数的引用
    const method = Array.prototype[key];
    // args就是 用户在形式上调用原生数组方法时候 其实调用的是这个匿名函数 传入的参数 
    arrayInstrumentations[key] = function (...args) {
        // 在下面的get实现中 Reflect中指定了this为 数组实例对象
        const arr = toRaw(this);
        // 上述3个操作 都需要遍历每个元素做对比 所以每个都需要触发一次get
        for (let i = 0, l = this.length; i < l; i++) {
            track(arr, "get" /* GET */, i + '');
        }
        // we run the method using the original args first (which may be reactive)
        // 获取原始结果 args有可能是其他data中声明的对象变成响应式代理了 所以还需要用原始值对象尝试一次 以免有误
        const res = method.apply(arr, args);
        if (res === -1 || res === false) {
            // if that didn't work, run it again using raw values.
            return method.apply(arr, args.map(toRaw));
        }
        else {
            return res;
        }
    };
});
// 首先 我们要知道一点 下面5个方法调用的时候会先取数组实例的length,然后再对数组的索引做对应的set操作
// 对于push 就是 arr[length] = newVal 触发trigger中的add事件
// 对于pop 就是 先取 arr[length -1] = val;因为是删除key 所以会触发调用deleteProperty 从而触发trigger中的delete事件
// 其他的方法分析类似 不过由于改变的位置在前面和任意位置,导致有更多元素要触发对应的 get 和 set 操作
// 不过最终的目的都是达到 通过下面5个方法更新对象后 它的观察者们可以重新更新就可以了
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(key => {
    const method = Array.prototype[key];
    arrayInstrumentations[key] = function (...args) {
        // 不需要追踪原生方法执行过程中对length或者元素get的操作
        pauseTracking();
        // this同上面的分析 指向数组实例 其实是个proxy代理 对它的修改 会触发trigger
        const res = method.apply(this, args);
        // 恢复
        resetTracking();
        return res;
    };
});
// 普通对象的代理拦截器handler属性中 get 方法的实现
function createGetter(isReadonly = false, shallow = false) {
    // 返回的get 闭包函数 持有调用 createGetter 时候的 2个自由变量 isReadonly shallow
    return function get(target, key, receiver) {
        // isReadonly 代表着不追踪变化 非响应式
        if (key === "__v_isReactive" /* IS_REACTIVE */) {
            return !isReadonly;
        }
        // 返回isReadonly即可
        else if (key === "__v_isReadonly" /* IS_READONLY */) {
            return isReadonly;
        }
        // __v_raw 获取 当前代理对象的原始关联对象
        // 当 receiver 上不存在属性a,而我们获取a的时候,恰好它的原型对象也是一个代理对象 这时候get方法会触发 而此时的target指向的是原型对象 而不是我们最初的target对象了
        // 所以这时候 (某个map).get(target) 是得不到我们之前建立好的关联关系的 目标 receiver 的
        // https://es6.ruanyifeng.com/#docs/proxy#Proxy-%E5%AE%9E%E4%BE%8B%E7%9A%84%E6%96%B9%E6%B3%95
        else if (key === "__v_raw" /* RAW */ &&
            receiver ===
            (isReadonly
                ? shallow
                    ? shallowReadonlyMap
                    : readonlyMap
                : shallow
                    ? shallowReactiveMap
                    : reactiveMap).get(target)) {
            return target;
        }
        // 数组实例的几个方法 调用对应的 arrayInstrumentations 中的实现即可
        const targetIsArray = isArray(target);
        if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) {
            // 第三个参数指定了 key对应的值如果是函数的话 函数的this就是 receiver 在这里 就是我们的数组实例对象
            return Reflect.get(arrayInstrumentations, key, receiver);
        }
        // 获取原始对象的值
        const res = Reflect.get(target, key, receiver);
        // 不予追踪的2类key
        if (isSymbol(key)
            ? builtInSymbols.has(key)
            : isNonTrackableKeys(key)) {
            return res;
        }
        // 触发track追踪get事件
        if (!isReadonly) {
            track(target, "get" /* GET */, key);
        }
        // 不再深度遍历继续代理下一层了
        if (shallow) {
            return res;
        }
        // 对于 ref 变量来说 存在一层value包裹 
        // 非数组内的ref 就展开ref的value得到原始值
        if (isRef(res)) {
            // ref unwrapping - does not apply for Array + integer key.
            const shouldUnwrap = !targetIsArray || !isIntegerKey(key);
            return shouldUnwrap ? res.value : res;
        }
        if (isObject(res)) {
            // Convert returned value into a proxy as well. we do the isObject check
            // here to avoid invalid value warning. Also need to lazy access readonly
            // and reactive here to avoid circular dependency.
            // 延迟追踪 只有get触发之后再视情况代理返回的值
            return isReadonly ? readonly(res) : reactive(res);
        }
        return res;
    };
}
// 包含ref类型变量赋值处理的set
const set = /*#__PURE__*/ createSetter();
// 不包含ref类型变量赋值处理的set
const shallowSet = /*#__PURE__*/ createSetter(true);
// 普通对象的代理拦截器handler属性中 set 方法的实现
function createSetter(shallow = false) {
    return function set(target, key, value, receiver) {
        // 旧值
        let oldValue = target[key];
        if (!shallow) {
            value = toRaw(value);
            oldValue = toRaw(oldValue);
            // 非数组情况下 旧值是ref类型 新值却不是 
            if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
                // 处理方案如下
                oldValue.value = value;
                return true;
            }
        }
        // 确定是否当前key存在
        const hadKey = isArray(target) && isIntegerKey(key)
            ? Number(key) < target.length
            : hasOwn(target, key);
        // 设置原始对象新值
        const result = Reflect.set(target, key, value, receiver);
        // don't trigger if target is something up in the prototype chain of original
        // 同上面get的分析 只有在对原始target触发的set操作的时候2者才想到
        if (target === toRaw(receiver)) {
            // 分情况触发2类事件
            if (!hadKey) {
                trigger(target, "add" /* ADD */, key, value);
            }
            else if (hasChanged(value, oldValue)) {
                trigger(target, "set" /* SET */, key, value, oldValue);
            }
        }
        return result;
    };
}
// 当我们删除对象的属性时候 下面会触发
// 普通对象的代理拦截器handler属性中 deleteProperty 方法的实现
function deleteProperty(target, key) {
    // 调用原生方法检测
    const hadKey = hasOwn(target, key);
    const oldValue = target[key];
    // 执行删除删除
    const result = Reflect.deleteProperty(target, key);
    if (result && hadKey) {
        // 触发delte事件
        trigger(target, "delete" /* DELETE */, key, undefined, oldValue);
    }
    return result;
}
// 当我们用 in 操作符  检测对象属性时候 下面会触发
// 值得注意的是,has()方法拦截的是HasProperty操作,而不是HasOwnProperty操作,即has()方法不判断一个属性是对象自身的属性,还是继承的属性。
// 另外,虽然for...in循环也用到了in运算符,但是has()拦截对for...in循环不生效。
function has(target, key) {
    const result = Reflect.has(target, key);
    if (!isSymbol(key) || !builtInSymbols.has(key)) {
        // 触发has事件的观察者
        track(target, "has" /* HAS */, key);
    }
    return result;
}
/**
 *  ownKeys()方法用来拦截对象自身属性的读取操作。具体来说,拦截以下操作。
    Object.getOwnPropertyNames()
    Object.getOwnPropertySymbols()
    Object.keys()
    for...in循环 
 */
function ownKeys(target) {
    // 追踪遍历操作类型事件
    track(target, "iterate" /* ITERATE */, isArray(target) ? 'length' : ITERATE_KEY);
    return Reflect.ownKeys(target);
}
// 由此我们构成了普通对象代理的handler拦截的几个属性实现
const mutableHandlers = {
    get,
    set,
    deleteProperty,
    has,
    ownKeys
};
// 只读handler
const readonlyHandlers = {
    get: readonlyGet,
    // 重写set 不可覆盖值
    set(target, key) {
        {
            console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`, target);
        }
        return true;
    },
    // 同上
    deleteProperty(target, key) {
        {
            console.warn(`Delete operation on key "${String(key)}" failed: target is readonly.`, target);
        }
        return true;
    }
};
// 只对get和set做shallow处理
const shallowReactiveHandlers = extend({}, mutableHandlers, {
    get: shallowGet,
    set: shallowSet
});
// Props handlers are special in the sense that it should not unwrap top-level
// refs (in order to allow refs to be explicitly passed down), but should
// retain the reactivity of the normal readonly object.
// 对get做 shallowReadonly 处理
const shallowReadonlyHandlers = extend({}, readonlyHandlers, {
    get: shallowReadonlyGet
});

// 转化目标对象 分别调用实际的实现方法
const toReactive = (value) => isObject(value) ? reactive(value) : value;
const toReadonly = (value) => isObject(value) ? readonly(value) : value;
const toShallow = (value) => value;
const getProto = (v) => Reflect.getPrototypeOf(v);
// 下面的方法都是 容器类型的对象 如 Map Set的代理handlers方法的实现了
// 拦截map的get操作
function get$1(target, key, isReadonly = false, isShallow = false) {
    // #1772: readonly(reactive(Map)) should return readonly + reactive version
    // of the value
    // 实际上所有的组件实例proxy上面的对象最终会包装一层代理对象 我们取值的最终对象是原始对象
    // key也是一样 因为是map key可能是对象
    target = target["__v_raw" /* RAW */];
    const rawTarget = toRaw(target);
    const rawKey = toRaw(key);
    if (key !== rawKey) {
        // 这里意味着 key 是代理对象 那我们就也添加 代理对象key的追踪
        !isReadonly && track(rawTarget, "get" /* GET */, key);
    }
    // 追踪原始key
    !isReadonly && track(rawTarget, "get" /* GET */, rawKey);
    // 原始map 的has
    const { has } = getProto(rawTarget);
    // 取值的发生的延迟代理 map的get操作 同普通对象的get一样
    const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;
    // 同普通对象的get 以2种key都尝试
    if (has.call(rawTarget, key)) {
        return wrap(target.get(key));
    }
    else if (has.call(rawTarget, rawKey)) {
        return wrap(target.get(rawKey));
    }
}
// 拦截都有的has操作
function has$1(key, isReadonly = false) {
    // this指向 map或者set的实例 分析见下文
    const target = this["__v_raw" /* RAW */];
    const rawTarget = toRaw(target);
    const rawKey = toRaw(key);
    // 分析同上
    if (key !== rawKey) {
        !isReadonly && track(rawTarget, "has" /* HAS */, key);
    }
    !isReadonly && track(rawTarget, "has" /* HAS */, rawKey);
    // 分析同上
    return key === rawKey
        ? target.has(key)
        : target.has(key) || target.has(rawKey);
}
// 拦截size操作
function size(target, isReadonly = false) {
    target = target["__v_raw" /* RAW */];
    // 追踪迭代事件
    !isReadonly && track(toRaw(target), "iterate" /* ITERATE */, ITERATE_KEY);
    return Reflect.get(target, 'size', target);
}
// 拦截 add 操作
function add(value) {
    // 分析同上
    value = toRaw(value);
    // this指向分析同上
    const target = toRaw(this);
    const proto = getProto(target);
    const hadKey = proto.has.call(target, value);
    if (!hadKey) {
        target.add(value);
        // 触发add类型的事件
        trigger(target, "add" /* ADD */, value, value);
    }
    return this;
}
// 拦截set操作
function set$1(key, value) {
    // 分析同上
    value = toRaw(value);
    const target = toRaw(this);
    const { has, get } = getProto(target);
    let hadKey = has.call(target, key);
    // !hadKey 意味着当前不存在这个 有可能是代理对象的key
    if (!hadKey) {
        // 以原始key再做一次has检测
        key = toRaw(key);
        hadKey = has.call(target, key);
    }
    else {
        // 存在可能以代理对象为key的情况下 做一次检测
        checkIdentityKeys(target, has, key);
    }
    const oldValue = get.call(target, key);
    target.set(key, value);
    if (!hadKey) {
        // 触发关注add操作的观察者们
        trigger(target, "add" /* ADD */, key, value);
    }
    else if (hasChanged(value, oldValue)) {
        // 值改变后 触发set类型的事件
        trigger(target, "set" /* SET */, key, value, oldValue);
    }
    return this;
}
// 拦截map的删除键值对操作
function deleteEntry(key) {
    // this的分析见下文
    const target = toRaw(this);
    const { has, get } = getProto(target);
    let hadKey = has.call(target, key);
    // 分析同上文
    if (!hadKey) {
        key = toRaw(key);
        hadKey = has.call(target, key);
    }
    else {
        checkIdentityKeys(target, has, key);
    }
    const oldValue = get ? get.call(target, key) : undefined;
    // forward the operation before queueing reactions
    const result = target.delete(key);
    if (hadKey) {
        // 触发delete类型的事件
        trigger(target, "delete" /* DELETE */, key, undefined, oldValue);
    }
    return result;
}
// 拦截清空操作
function clear() {
    const target = toRaw(this);
    // 之前是否有存储
    const hadItems = target.size !== 0;
    // 保留未删除之前的数据备份
    const oldTarget = isMap(target)
            ? new Map(target)
            : new Set(target)
        ;
    // forward the operation before queueing reactions
    const result = target.clear();
    if (hadItems) {
        // 触发clear类型的事件 注意最后一个参数 oldTarget
        trigger(target, "clear" /* CLEAR */, undefined, undefined, oldTarget);
    }
    return result;
}
// 构造我们定义的forEach函数
function createForEach(isReadonly, isShallow) {
    // 2个用于选择 响应式类型的 自由变量
    // 实际执行的是下面这个函数 注意 用户传入可以有2个参数 第二个参数可以绑定任意对象作为第一个参数函数的this 
    // https://es6.ruanyifeng.com/#docs/set-map#Map
    return function forEach(callback, thisArg) {
        const observed = this;
        // 取得实例的原始对象
        const target = observed["__v_raw" /* RAW */];
        const rawTarget = toRaw(target);
        // 选择合适的响应式转化函数
        const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;
        // 遍历操作需要追踪
        !isReadonly && track(rawTarget, "iterate" /* ITERATE */, ITERATE_KEY);
        // 执行原始方法
        return target.forEach((value, key) => {
            // important: make sure the callback is
            // 1. invoked with the reactive map as `this` and 3rd arg
            // 2. the value received should be a corresponding reactive/readonly.
            // 以用户的this为准 
            // 同时由于触发了key和value的get 我们先对他们做响应式代理 以建立依赖收集
            // 最后一个参数 也是实例对象本身 同见上面的链接解释
            return callback.call(thisArg, wrap(value), wrap(key), observed);
        });
    };
}
// 用到了迭代器实现的几个含有遍历操作的方法 entries keys values
function createIterableMethod(method, isReadonly, isShallow) {
    return function (...args) {
        const target = this["__v_raw" /* RAW */];
        const rawTarget = toRaw(target);
        // 是否是map实例
        const targetIsMap = isMap(rawTarget);
        const isPair = method === 'entries' || (method === Symbol.iterator && targetIsMap);
        // map的keys只获取key
        const isKeyOnly = method === 'keys' && targetIsMap;
        // 这个方法实际上都是返回一个迭代器对象
        const innerIterator = target[method](...args);
        // 选择合适的响应式函数转化参数
        const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;
        // 追踪对应的遍历操作
        !isReadonly &&
            track(rawTarget, "iterate" /* ITERATE */, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY);
        // return a wrapped iterator which returns observed versions of the
        // values emitted from the real iterator
        // 按照迭代器协议实现
        return {
            // iterator protocol
            next() {
                // 调用原生的迭代器对象的方法
                const { value, done } = innerIterator.next();
                return done
                    ? { value, done }
                    : {
                        // 触发了参数的get 建立依赖收集
                        value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value),
                        done
                    };
            },
            // iterable protocol
            [Symbol.iterator]() {
                return this;
            }
        };
    };
}
// 对只读对象 用修改操作方法的是时候 添加警告信息
function createReadonlyMethod(type) {
    return function (...args) {
        {
            const key = args[0] ? `on key "${args[0]}" ` : ``;
            console.warn(`${capitalize(type)} operation ${key}failed: target is readonly.`, toRaw(this));
        }
        return type === "delete" /* DELETE */ ? false : this;
    };
}
// 基础容器的handlers 下面其他几个都是对应 只读 浅层的版本
const mutableInstrumentations = {
    get(key) {
        return get$1(this, key);
    },
    get size() {
        return size(this);
    },
    has: has$1,
    add,
    set: set$1,
    delete: deleteEntry,
    clear,
    forEach: createForEach(false, false)
};
const shallowInstrumentations = {
    get(key) {
        return get$1(this, key, false, true);
    },
    get size() {
        return size(this);
    },
    has: has$1,
    add,
    set: set$1,
    delete: deleteEntry,
    clear,
    forEach: createForEach(false, true)
};
const readonlyInstrumentations = {
    get(key) {
        return get$1(this, key, true);
    },
    get size() {
        return size(this, true);
    },
    // 因为多一个参数比上面的
    has(key) {
        return has$1.call(this, key, true);
    },
    // 只读不允许下面的操作
    add: createReadonlyMethod("add" /* ADD */),
    set: createReadonlyMethod("set" /* SET */),
    delete: createReadonlyMethod("delete" /* DELETE */),
    clear: createReadonlyMethod("clear" /* CLEAR */),
    forEach: createForEach(true, false)
};
const shallowReadonlyInstrumentations = {
    get(key) {
        return get$1(this, key, true, true);
    },
    get size() {
        return size(this, true);
    },
    has(key) {
        return has$1.call(this, key, true);
    },
    add: createReadonlyMethod("add" /* ADD */),
    set: createReadonlyMethod("set" /* SET */),
    delete: createReadonlyMethod("delete" /* DELETE */),
    clear: createReadonlyMethod("clear" /* CLEAR */),
    forEach: createForEach(true, true)
};
// 创建几个返回迭代器对象的方法
const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator];
iteratorMethods.forEach(method => {
    mutableInstrumentations[method] = createIterableMethod(method, false, false);
    readonlyInstrumentations[method] = createIterableMethod(method, true, false);
    shallowInstrumentations[method] = createIterableMethod(method, false, true);
    shallowReadonlyInstrumentations[method] = createIterableMethod(method, true, true);
});
// 容器对象任意方法key get操作的统一拦截handler
function createInstrumentationGetter(isReadonly, shallow) {
    // 选择合适的基础容器对象 包含所有的handlers实现
    const instrumentations = shallow
        ? isReadonly
            ? shallowReadonlyInstrumentations
            : shallowInstrumentations
        : isReadonly
            ? readonlyInstrumentations
            : mutableInstrumentations;
    return (target, key, receiver) => {
        // 同普通对象的分析
        if (key === "__v_isReactive" /* IS_REACTIVE */) {
            return !isReadonly;
        }
        else if (key === "__v_isReadonly" /* IS_READONLY */) {
            return isReadonly;
        }
        else if (key === "__v_raw" /* RAW */) {
            return target;
        }
        // 我们自己实现的拦截handler的key 才调用我们的实现 其余的用原生的
        return Reflect.get(hasOwn(instrumentations, key) && key in target
            ? instrumentations
            : target, key, receiver);
    };
}
// 构造对应的几类handlers对象
const mutableCollectionHandlers = {
    get: createInstrumentationGetter(false, false)
};
const shallowCollectionHandlers = {
    get: createInstrumentationGetter(false, true)
};
const readonlyCollectionHandlers = {
    get: createInstrumentationGetter(true, false)
};
const shallowReadonlyCollectionHandlers = {
    get: createInstrumentationGetter(true, true)
};
// 检测map的key的有效性
function checkIdentityKeys(target, has, key) {
    const rawKey = toRaw(key);
    // 存储响应式map仓库中发现 同时存在以 某个对象key及它的代理对象 为key的情况
    if (rawKey !== key && has.call(target, rawKey)) {
        const type = toRawType(target);
        console.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.`);
    }
}

// 之前有个 targetMap 是被观察者和观察者之间的联系
// 下面几个则是 被代理原始对象和代理对象的之间的联系存储对象
const reactiveMap = new WeakMap();
const shallowReactiveMap = new WeakMap();
const readonlyMap = new WeakMap();
const shallowReadonlyMap = new 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 */;
    }
}
// 调用上面的方法
function getTargetType(value) {
    // 不可拓展的对象 和 vue忽略对象
    return value["__v_skip" /* SKIP */] || !Object.isExtensible(value)
        ? 0 /* INVALID */
        : targetTypeMap(toRawType(value));
}
// 下面4个对应不同的参数而已
// 响应式函数高级调用api
function reactive(target) {
    // if trying to observe a readonly proxy, return the readonly version.
    if (target && target["__v_isReadonly" /* IS_READONLY */]) {
        return target;
    }
    // 调用内部实现
    return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
}
/**
 * Return a shallowly-reactive copy of the original object, where only the root
 * level properties are reactive. It also does not auto-unwrap refs (even at the
 * root level).
 */
function shallowReactive(target) {
    return createReactiveObject(target, false, shallowReactiveHandlers, shallowCollectionHandlers, shallowReactiveMap);
}
/**
 * Creates a readonly copy of the original object. Note the returned copy is not
 * made reactive, but `readonly` can be called on an already reactive object.
 */
function readonly(target) {
    return createReactiveObject(target, true, readonlyHandlers, readonlyCollectionHandlers, readonlyMap);
}
/**
 * Returns a reactive-copy of the original object, where only the root level
 * properties are readonly, and does NOT unwrap refs nor recursively convert
 * returned properties.
 * This is used for creating the props proxy object for stateful components.
 */
function shallowReadonly(target) {
    return createReactiveObject(target, true, shallowReadonlyHandlers, shallowReadonlyCollectionHandlers, shallowReadonlyMap);
}
// 实际的实现在这里
function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers, proxyMap) {
    // 只代理object
    if (!isObject(target)) {
        {
            console.warn(`value cannot be made reactive: ${String(target)}`);
        }
        return target;
    }
    // target is already a Proxy, return it.
    // exception: calling readonly() on a reactive object
    if (target["__v_raw" /* RAW */] &&
        !(isReadonly && target["__v_isReactive" /* IS_REACTIVE */])) {
        return target;
    }
    // target already has corresponding Proxy
    // 无需反复代理同一个对象
    const existingProxy = proxyMap.get(target);
    if (existingProxy) {
        return existingProxy;
    }
    // only a whitelist of value types can be observed.
    const targetType = getTargetType(target);
    if (targetType === 0 /* INVALID */) {
        return target;
    }
    // 建立代理
    const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers);
    // 建立map对应
    proxyMap.set(target, proxy);
    // 返回代理对象
    return proxy;
}
function isReactive(value) {
    if (isReadonly(value)) {
        return isReactive(value["__v_raw" /* RAW */]);
    }
    return !!(value && value["__v_isReactive" /* IS_REACTIVE */]);
}
function isReadonly(value) {
    return !!(value && value["__v_isReadonly" /* IS_READONLY */]);
}
function isProxy(value) {
    return isReactive(value) || isReadonly(value);
}
// 由于存在多层代理 所以需要递归调用toRaw一直找到最底层的原始对象
function toRaw(observed) {
    return ((observed && toRaw(observed["__v_raw" /* RAW */])) || observed);
}
// 标记这始终不需要代理它 一直保持原始对象
function markRaw(value) {
    def(value, "__v_skip" /* SKIP */, true);
    return value;
}
// 转化为响应式代理对象
const convert = (val) => isObject(val) ? reactive(val) : val;
// ref型对象标识
function isRef(r) {
    return Boolean(r && r.__v_isRef === true);
}
// 外部调用api
function ref(value) {
    return createRef(value);
}
// 浅层ref对象 意味着不做递归响应式代理 只代理value这一层
function shallowRef(value) {
    return createRef(value, true);
}
// ref具体实现 总体来说就是一层value对象的包裹 然后拦截get和set value的操作
class RefImpl {
    constructor(_rawValue, _shallow = false) {
        // 原始值
        this._rawValue = _rawValue;
        // 浅层标志
        this._shallow = _shallow;
        // 自身标记
        this.__v_isRef = true;
        // 不继续代理了
        this._value = _shallow ? _rawValue : convert(_rawValue);
    }
    get value() {
        // 对 someRef.value 这样的取值操作 触发我们想要的get追踪 等于对原始任意值多了一层对象包裹
        track(toRaw(this), "get" /* GET */, 'value');
        return this._value;
    }
    set value(newVal) {
        if (hasChanged(toRaw(newVal), this._rawValue)) {
            this._rawValue = newVal;
            // 不继续代理新值
            this._value = this._shallow ? newVal : convert(newVal);
            // 触发set类型事件
            trigger(toRaw(this), "set" /* SET */, 'value', newVal);
        }
    }
}
// 对外暴露的高级api调用
function createRef(rawValue, shallow = false) {
    if (isRef(rawValue)) {
        return rawValue;
    }
    return new RefImpl(rawValue, shallow);
}
// 手动触发 与ref关联的副作用函数
function triggerRef(ref) {
    trigger(toRaw(ref), "set" /* SET */, 'value', ref.value );
}
// 接触ref包裹 返回原始对象
function unref(ref) {
    return isRef(ref) ? ref.value : ref;
}
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);
        }
    }
};
// 对ref类型对象做一层代理 主要是对ref对象的get操作 返回去ref的值 set操作 根据旧值和新值的对比来处理
function proxyRefs(objectWithRefs) {
    return isReactive(objectWithRefs)
        ? objectWithRefs
        : new Proxy(objectWithRefs, shallowUnwrapHandlers);
}
// 自定义ref实现
class CustomRefImpl {
    constructor(factory) {
        this.__v_isRef = true;
        // 对应文档中描述的2个内置函数 需要用户在get和set中调用
        const { get, set } = factory(() => track(this, "get" /* GET */, 'value'), () => trigger(this, "set" /* SET */, 'value'));
        // 绑定
        this._get = get;
        this._set = set;
    }
    get value() {
        return this._get();
    }
    set value(newVal) {
        this._set(newVal);
    }
}
// 外部调用api
function customRef(factory) {
    return new CustomRefImpl(factory);
}
// 把一个响应式对象 转化为 每个对应的key的值都是ref对象
function toRefs(object) {
    if (!isProxy(object)) {
        console.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] = toRef(object, key);
    }
    return ret;
}
// 根据原始对象仓库和对应的key 构造ref对象的实现
class ObjectRefImpl {
    constructor(_object, _key) {
        this._object = _object;
        this._key = _key;
        this.__v_isRef = true;
    }
    // get 和 set 操作都是对原对象仓库的操作
    // 由于 _object 是响应式的 所以还是会触发对应的track和trigger
    get value() {
        return this._object[this._key];
    }
    set value(newVal) {
        this._object[this._key] = newVal;
    }
}
// 单个key生成对应的ref对象
function toRef(object, key) {
    return isRef(object[key])
        ? object[key]
        : new ObjectRefImpl(object, key);
}

// computed对象实现
class ComputedRefImpl {
    constructor(getter, _setter, isReadonly) {
        // 绑定setter
        this._setter = _setter;
        // 懒更新 只有这个为true get操作才会取最新的值 否则一直返回之前的缓存值
        this._dirty = true;
        // 自我类型标识
        this.__v_isRef = true;
        // 创建响应式effect 注意入参getter函数 作为 effect每次在触发更新后执行的目标函数
        this.effect = effect(getter, {
            // 并不马上执行 除非触发了get操作
            lazy: true,
            // 当computed对象所依赖的对象发生改变后 scheduler 会因为被依赖变量的trigger的执行而执行
            scheduler: () => {
                if (!this._dirty) {
                    // 通知 可以重新取新值了
                    this._dirty = true;
                    // 触发关注computed对象的观察者们 可以更新了 这时候render重新执行 重新触发下面的get 就可以得到computed对象的新值了
                    trigger(toRaw(this), "set" /* SET */, 'value');
                }
            }
        });
        this["__v_isReadonly" /* IS_READONLY */] = isReadonly;
    }
    get value() {
        // the computed ref may get wrapped by other proxies e.g. readonly() #3376
        // 取得computed实例对象
        const self = toRaw(this);
        // 只有上面因为getter的依赖发送改变而引起了 effect的重新执行而导致scheduler执行了 或者 初始化第一次取值 才会进入下面逻辑 去计算一次getter得到新值
        if (self._dirty) {
            self._value = this.effect();
            // 重新进入懒更新状态
            self._dirty = false;
        }
        // 追踪谁依赖当前computed实例对象
        track(self, "get" /* GET */, 'value');
        return self._value;
    }
    set value(newValue) {
        this._setter(newValue);
    }
}
// 外部调用api 我们可以传入一个getter或者包含 getter setter的对象
function computed(getterOrOptions) {
    let getter;
    let setter;
    // 只传一个getter
    if (isFunction(getterOrOptions)) {
        getter = getterOrOptions;
        setter = () => {
                console.warn('Write operation failed: computed value is readonly');
            }
            ;
    }
    // 第二种情况
    else {
        getter = getterOrOptions.get;
        setter = getterOrOptions.set;
    }
    return new ComputedRefImpl(getter, setter, isFunction(getterOrOptions) || !getterOrOptions.set);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions