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`)
}
}
下一章 处理依赖收集