vue3源码(2)-reactive,readonly,shallowReactive,shallowReadonly响应式api

83 阅读3分钟

reactivity文件夹下创建文件index.ts,reactive.ts

export {
  reactive,
  shallowReactive,
  readonly,
  shallowReadonly,
} from './reactive'

在reactive文件中创建四个方法,暴露出去,给index用于导出

export const reactive = <T extends object>(target: T): T => {
}
export const shallowReactive = <T extends object>(target: T): T => {
}
export const readonly = <T extends object>(target: T): T => {
}
export const shallowReadonly = <T extends object>(target: T): T => {
}

reactive是全部响应式,shallowReactive是浅响应式,readonly是全部只读响应式,shallowReadonly是浅只读响应式。意思是reactive有proxy的set和get拦截,readonly只需要proxy的get拦截。shallow只拦截第一层。

实现响应式代理

这四个方法接收一个需要代理的目标,然后返回一个该目标的代理。

柯里化:根据传入的不同的参,返回不同的结果。

四个方法的返回值 createReactiveObject(target, false, shallowReadonlyHandlers) 第一个参数是代理的目标,第二个参数是是否只读,第三个参数是映射,及代理的详细配置

WeakMap 是一种键值对的集合,其中的键必须是对象或非全局注册的符号,且值可以是任意的 JavaScript 类型,并且不会创建对它的键的强引用。换句话说,一个对象作为 WeakMap 的键存在,不会阻止该对象被垃圾回收。一旦一个对象作为键被回收,那么在 WeakMap 中相应的值便成为了进行垃圾回收的候选对象,只要它们没有其他的引用存在。唯一可以作为 WeakMap 的键的类型是非全局注册的符号,因为非全局注册的符号是保证唯一的,并且不能被重新创建。

const reactiveMap = new WeakMap()  //key必须是对象 自动垃圾回收
const readonlyMap = new WeakMap() 
//实现代理
const createReactiveObject = (target: any, isReadonly: boolean, baseHandlers: {}) => {
  if (!isObject(target)) {   //判断是否是对象 isObject是自定义的一个方法,用于判断是否是对象
    return target
  }

  const proxymap = isReadonly ? readonlyMap : reactiveMap
  const proxyEs = proxymap.get(target)
  if (proxyEs) {
    return proxyEs
  }
  const proxy = new Proxy(target, baseHandlers)
  proxymap.set(target, proxy) //存放
  return proxy
}
  export const isObject = (value: unknown): boolean => {
  return typeof value === 'object' && value !== null;
}

创建2个weakMap用于存放代理目标值。

如果不是对象,就将目标返回。

判断是否只读,存放于不同的weakMap内。

如果weakMap已经有了目标值,就return出去,没有就存进去,最后返回proxy代理对象

处理映射

新建一个文件baseHandler.ts,这个文件需要导出四个映射,给reatcive.ts使用

export const reactiveHandlers = {
}
export const shallowReactiveHandlers = {
}
export const readonlyHandlers = {
}
export const shallowReadonlyHandlers = {
}

完整的reatcive.ts文件

import { isObject } from "@vue/shared"
import { reactiveHandlers, shallowReactiveHandlers, readonlyHandlers, shallowReadonlyHandlers } from "./baseHandlers"
export const reactive = <T extends object>(target: T): T => {
  return createReactiveObject(target, false, reactiveHandlers)
}
export const shallowReactive = <T extends object>(target: T): T => {
  return createReactiveObject(target, false, shallowReactiveHandlers)
}
export const readonly = <T extends object>(target: T): T => {
  return createReactiveObject(target, false, readonlyHandlers)
}
export const shallowReadonly = <T extends object>(target: T): T => {
  return createReactiveObject(target, false, shallowReadonlyHandlers)
}
const reactiveMap = new WeakMap()  //key必须是对象 自动垃圾回收
const readonlyMap = new WeakMap()  
//实现代理
const createReactiveObject = (target: any, isReadonly: boolean, baseHandlers: {}) => {
  if (!isObject(target)) {
    return target
  }
  const proxymap = isReadonly ? readonlyMap : reactiveMap
  const proxyEs = proxymap.get(target)
  if (proxyEs) {
    return proxyEs
  }
  const proxy = new Proxy(target, baseHandlers)
  proxymap.set(target, proxy) //存放
  return proxy
}

readonly只有get方法,set方法全部返回一个报错 柯里化get和set

const get = createGetter()    //默认不传就是全false ,两个参数,一个是是否只读,一个是否是浅
const shallowGet = createGetter(false, true)  
const readonlyGet = createGetter(true)
const shallowReadonlyGet = createGetter(true, true)
const set = createSetter()
const shallowSet = createSetter(true)
const createGetter = (isReadonly = false, isShallow = false) => {
  return function get(target: any, key: any, receiver: Object) {
    const res = Reflect.get(target, key, receiver)
    if (!isReadonly) {
     //  track(target,TrackOpType.GET,key)          
     //收集依赖,不是只读,就有set方法,set方法的时候就需要对依赖进行收集
    }
    if (isShallow) {
      return res
    }
    if (isObject(res)) {  
    // 面试考点:vue3对比vue2响应式嵌套对象优化策略。
    // vue2是全部递归然后全部代理,vue3是当你访问子对象时,才会对他进行代理,否则就不代理。
      return isReadonly ? readonly(res) : reactive(res)
    }
    return res
  }
}
const createSetter = (isShallow: boolean = false) => {
  return function set(target: any, key: any, value: any, receiver: Object) {
    const res = Reflect.set(target, key, value, receiver)
    return res
  }

}

export const reactiveHandlers = {
  get,
  set
}
export const shallowReactiveHandlers = {
  get: shallowGet,
  set: shallowSet

}
export const readonlyHandlers = {
  get: readonlyGet,
  set: (target: any, key: any, value: any) => {
    return console.warn(`set on key ${key} failed`)
  }
}
export const shallowReadonlyHandlers = {
  get: shallowReadonlyGet,
  set: (target: any, key: any, value: any) => {
    return console.warn(`set on key ${key} failed`)
  }
}

下一章 处理依赖收集