vlambda博客
学习文章列表

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 }});console.log(state.age, state);let state2 = shallowReactive({ name: 'leungboasing', age: { num: 25 }});console.log(state2.age, state);let state3 = readonly({ name: 'leungboasing', age: { num: 25 }});state3.age.num = 3// console.log(state);let state4 = shallowReadonly({ name: 'leungboasing', age: { num: 25 }});state4.age = 4;state4.age.num = 4;console.log( 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)