这一次的内容比较轻松,首先是让我们上一节实现的isReactive、isReadonly实现嵌套的功能,然后实现shallowReadonly(不支持嵌套),最后是isProxy。
isReactive / isReadonly 嵌套
什么是嵌套呢,先来感受一下:
it('nested reactives', () => {
const original = {
nested: {
foo: 1
},
array: [{ bar: 2 }]
};
const observed = reactive(original);
// 支持嵌套
expect(isReactive(observed.nested)).toBe(true);
expect(isReactive(observed.array)).toBe(true);
expect(isReactive(observed.array[0])).toBe(true);
});
即:如果响应式对象的某个属性值也是对象,那么使用isReactive判断这个对象时,也应该得到true。
要做到这点,只需要访问响应式对象的属性时,判断是不是对象,如果是对象,getter要先把对象用reactive或readonly包裹,然后再返回。
const isObject = (val) => {
return val !== null && typeof val === 'object';
};
完整的createGetter函数在说完shallowReadonly后一起给出。
shallowReadonly
有些时候,出于性能考虑,只想要最外一层对象是响应式的,而且还得是readonly。此时要避免走入用reactice或readonly包裹的逻辑,而且和readonly一样不执行track。
添加shallow,用于控制上述行为。
const shallowReadonlyGet = createGetter(true, true);
function createGetter(isReadonly = false, shallow = false) {
return function (target, key) {
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly;
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly;
}
const res = Reflect.get(target, key);
// shallow直接返回
if (shallow) {
return res;
}
// 依赖收集
if (!isReadonly) {
track(target, key);
}
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res);
}
return res;
};
}
// extend就是Object.assign()
// 因为shallowReadonly和readonly的setter一样,都会抛出警告,所以复用
export const shallowReadonlyHandlers = extend({}, readonlyHandlers, {
get: shallowReadonlyGet
});
isProxy
isProxy的逻辑十分简单:
export function isProxy(value) {
return isReactive(value) || isReadonly(value);
}