isProxy
思考:
- vue3 isProxy的作用是用来判断对象是否为reactive和readonly对象
- 我们已经实现了 isReactive 和 isReadonly 了,其实就是拿这两个做判断,比较简单
index.ts
+ export function isProxy(raw) {
+ // 双取反是为了兼容返回undefined
+ return isReadonly(raw) || isReactive(raw);
+ }
shallowReadonly & shallowReactive
思考
- 其实这两个都很类似,只做首层代理,不做深层的转换
- readonly 深层数据变化不会被拦截
- reacitve 深层双向绑定不会触发
回顾前面实现的代码,我们在Proxy get时,做了对象判断,对嵌套对象做了深度转换,以保证深度嵌套的数据能够被侦听(reactive)和拦截(readonly)
baseHandlers.ts - createdGetter
* @Author: Lin zefan
* @Date: 2022-03-16 18:30:25
* @LastEditTime: 2022-03-20 11:55:59
* @LastEditors: Lin zefan
* @Description:
* @FilePath: \mini-vue3\src\reactivity\baseHandlers.ts
*
*/
// 有这么一行判断
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res);
}
根据我们前面的思考的几个点,那我们是不是可以在这里加个标识,如果shallow为true,就不做深度转换。
实现
index.ts
/*
* @Author: Lin zefan
* @Date: 2022-03-15 13:08:22
* @LastEditTime: 2022-03-20 11:07:51
* @LastEditors: Lin zefan
* @Description:
* @FilePath: \mini-vue3\src\reactivity\index.ts
*
*/
import {
mutableHandles,
readonlyHandles,
+ shallowReadonlyHandles,
+ shallowReactiveHandles
} from "./baseHandlers";
export const enum ReactiveEnum {
IS_REACTIVE = "__v_isReactive",
IS_READONLY = "__v_isReadonly",
}
function createdBaseHandler(raw, baseHandler) {
return new Proxy(raw, baseHandler);
}
export function reactive(raw) {
return createdBaseHandler(raw, mutableHandles);
}
export function readonly(raw) {
return createdBaseHandler(raw, readonlyHandles);
}
+ export function shallowReactive(raw) {
+ return createdBaseHandler(raw, shallowReactiveHandles);
+ }
+ export function shallowReadonly(raw) {
+ return createdBaseHandler(raw, shallowReadonlyHandles);
+ }
export function isReadonly(raw) {
// 双取反是为了兼容返回undefined
return !!raw[ReactiveEnum.IS_READONLY];
}
export function isReactive(raw) {
// 双取反是为了兼容返回undefined
return !!raw[ReactiveEnum.IS_REACTIVE];
}
export function isProxy(raw) {
// 双取反是为了兼容返回undefined
return isReadonly(raw) || isReactive(raw);
}
baseHandlers.ts
/*
* @Author: Lin zefan
* @Date: 2022-03-16 18:30:25
* @LastEditTime: 2022-03-20 11:55:59
* @LastEditors: Lin zefan
* @Description:
* @FilePath: \mini-vue3\src\reactivity\baseHandlers.ts
*
*/
import { reactive, ReactiveEnum, readonly } from ".";
import { extend, isObject } from "../shared";
import { track, trigger } from "./effect";
+ function createdGetter(isReadonly = false, shallow = false) {
return function (target, key, receiver) {
const res = Reflect.get(target, key, receiver);
// 判断是否为reactive
if (key === ReactiveEnum.IS_REACTIVE) {
return !isReadonly;
}
// 判断是否为readonly
if (key === ReactiveEnum.IS_READONLY) {
return isReadonly;
}
+ /** 嵌套转换判断, 思考
+ * 1. 如果shallow为true,那就不进行深度转换
+ * 2. 没有被深度转换的,是一个普通对象,不会二次转换
+ * 3. 即没有readonly深度拦截, 没有reactive的深度对象响应(没有被收集)
+ */
+ if (isObject(res) && !shallow) {
+ return isReadonly ? readonly(res) : reactive(res);
+ }
// 如果是readonly,不会进行收集
!isReadonly && track(target, key);
return res;
};
}
function createdSetter() {
return function (target, key, value, receiver) {
const res = Reflect.set(target, key, value, receiver);
trigger(target, key);
return res;
};
}
// 避免多次创建,这里直接用变量接收~
const get = createdGetter();
const set = createdSetter();
const readonlyGet = createdGetter(true);
+ const shallowReactiveGet = createdGetter(false, true);
+ const shallowReadonlyGet = createdGetter(true, true);
export const mutableHandles = {
get,
set,
};
export const readonlyHandles = {
get: readonlyGet,
set(target, key, value, receiver) {
// 给一个警告
console.warn(`${key}是只读的,因为被readonly包裹了`, target);
return true;
},
};
+ export const shallowReadonlyHandles = extend({}, readonlyHandles, {
+ get: shallowReadonlyGet,
+ });
+ export const shallowReactiveHandles = extend({}, mutableHandles, {
+ get: shallowReactiveGet,
+ });