Open
Description
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
Labels
No labels