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}});= 3console.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会报异常// 是不是深度的// 创建getfunction 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;}}// 创建setfunction 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)
