Vue3.0源码剖析-响应式对象
1、reactive API
响应式对象的主要4个api分别为
let {reactive, shallowReadonly, shallowReactive, readonly} = VueReactivity;
reactive -- 深度监听
shallowReactive -- 浅监听
shallowReadonly -- 浅监听且只读
readonly -- 只读
2、用法示例:
let state = reactive({
name: 'leungboasing',
age: {
num: 25
}
});
state);
let state2 = shallowReactive({
name: 'leungboasing',
age: {
num: 25
}
});
state);
let state3 = readonly({
name: 'leungboasing',
age: {
num: 25
}
});
3 =
console.log(state);
let state4 = shallowReadonly({
name: 'leungboasing',
age: {
num: 25
}
});
4; =
4; =
state4.age.num);
3、 源码实现
reactive.ts:
import {isObject} from '@vue/shared';
import {mutableHandlers, readonlyHandlers, shallowReadonlyHandlers, shallowReactiveHandlers} from './baseHandlers'
// 深度监听
export function reactive(target) {
return createReactiveObject(target, false, mutableHandlers)
}
// 浅监听
export function shallowReactive(target) {
return createReactiveObject(target, false, shallowReactiveHandlers)
}
// 浅监听且只读
export function shallowReadonly(target) {
console.log(shallowReadonlyHandlers);
return createReactiveObject(target, true, shallowReadonlyHandlers)
}
// 只读
export function readonly(target) {
console.log(readonlyHandlers);
return createReactiveObject(target, true, readonlyHandlers)
}
const reactiveMap = new WeakMap(); // 会自动垃圾回收, 不会造成内存泄漏, 存储的key只能是对象
const readonlyMap = new WeakMap();
// 不仅是否仅读, 是否深代理, 都需要创建一个 proxy, 并且最核心都需要拦截数据的读取与及修改(set, get)
export function createReactiveObject(target, isReadonly, baseHandlers) {
// 如果目标不是对象, 没法拦截, reactive这个api只能拦截对象类型
if(!isObject(target)) {
return target;
}
// 如果某个对象已经被代理过了 就不要再次代理了
// 也可能一个对象被 深代理, 又被只读代理
const proxyMap = isReadonly ? readonlyMap : reactiveMap;
// 在代理列表里面查找结果
const exisitProxy = proxyMap.get(target);
// 如果已经被代理, 就返回代理结果
if(exisitProxy) {
return exisitProxy;
}
const proxy = new Proxy(target, baseHandlers);
// 设置代理列表
proxyMap.set(target, proxy);
return proxy;
}
baseHandlers.ts
// 实现 reactive, readonly, shallowReactive, shallowReadonly 4个基础api 的 proxy 的 拦截器功能
import {extend, hasChanged, hasOwn, isArray, isIntegerKey, isObject} from '@vue/shared';
import {reactive, readonly} from "./reactivity";
import {track, trigger} from './effect';
import {TrackOptypes, TriggerOrType} from "./operators";
// 是否只读, 进度的属性set会报异常
// 是不是深度的
// 创建get
function createGetter(isReadonly = false, shallow = false) {
return function get(target, key, receiver) {
// 目标了, key, 代理对象
// Reflect 优势
// 后续Object上的方法, 都会迁移到Reflect
// target[key] = value 方法设置值可能会失败, 且并不会报异常, 也没有返回值标识
// Reflect 方法具备返回值
// Reflect 使用可以不使用 proxy
// ES6 新增
const result = Reflect.get(target, key, receiver); // 相当于target[key]
if(shallow) {
return result;
}
// vue3.0 是懒循环代理, 2.0是一开始就循环, 性能优化
if(isObject(result)) {
return isReadonly ? readonly(result) : reactive(result);
}
return result;
}
}
// 创建set
function createSetter(isShallow = false) {
return function set(target, key, value, receiver) {
// 保存old的值
// const oldValue = target[key];
const oldValue = target[key];
return result;
}
}
// 拦截获取
const get = createGetter();
const shallowGet = createGetter(false, true);
const readonlyGet = createGetter(true);
const shallowReadonlyGet = createGetter(true, true);
// 拦截设置
const set = createSetter();
const shallowSet = createSetter(true);
// 只读拦截器
const readonlyObj = {
set: (target, key) => {
console.warn(`set on key ${key} failed, because this target is readonly`)
}
}
// 深监听
export const mutableHandlers = {
get,
set
}
// 浅监听
export const shallowReactiveHandlers = {
get: shallowGet,
set: shallowSet
}
// 深度只读监听
export const readonlyHandlers = extend({
get: readonlyGet
}, readonlyObj)
// 浅只读监听
export const shallowReadonlyHandlers = extend({
get: shallowReadonlyGet,
}, readonlyObj)