We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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); }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
vue中的响应式主要是通过把目标对象变成代理对象,同时设置对应属性的handlers来控制的,我们看下实际vue中用到的handlers都是怎么实现的,以及ref对象和computed对象的实现:
The text was updated successfully, but these errors were encountered: