BaseHandlers
这里照顾一下新同学,科普一下 handler,音译为处理器,我们也可以理解为处理器,在Proxy这篇文章中我们了解到 Proxy(target, handlers) 接收两个参数,target 为目标对象,handlers 就是针对我们对 target 操作的一系列行为同时做一些处理
正文
在 basehandlers 中包含了四种 handler
- mutableHandlers 可变处理
- readonlyHandlers 只读处理
- shallowReactiveHandlers 浅观察处理(只观察目标对象的第一层属性)
- shallowReadonlyHandlers 浅观察 && 只读处理
其中 readonlyHandlers shallowReactiveHandlers shallowReadonlyHandlers 都是 mutableHandlers 的变形版本,这里我们主要针对 mutableHandlers 展开
mutableHandlers
我们还是选择从定义看起
export const mutableHandlers: ProxyHandler<object> = {get, // 用于拦截对象的读取属性操作set, // 用于拦截对象的设置属性操作deleteProperty, // 用于拦截对象的删除属性操作has, // 检查一个对象是否拥有某个属性ownKeys // 针对 getOwnPropertyNames, getOwnPropertySymbols, keys 的代理方法}
get set 代码量稍微多点,我们先来点轻松的
/*** @description: 用于拦截对象的删除属性操作* @param {target} 目标对象* @param {key} 键值* @return {Boolean}*/function deleteProperty(target: object, key: string | symbol): boolean {// hasOwn 的实现放下方了,检查一个对象是否包含当前keyconst hadKey = hasOwn(target, key)const oldValue = (target as any)[key]// Reflect 作用在于完成目标对象的默认,这里即指删除const result = Reflect.deleteProperty(target, key)// 如果该值被成功删除则调用 trigger,// trigger 为 effect 里的方法,effect 为 reactive 的核心, 后面会讲到if (result && hadKey) {trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue)}return result}/*** @description: 检查一个对象是否拥有某个属性* @param {target} 目标对象* @param {key} 键值* @return {Boolean}*/function has(target: object, key: string | symbol): boolean {const result = Reflect.has(target, key)// track 也为 effect 里的方法,effect 为 reactive 的核心, 后面会讲到track(target, TrackOpTypes.HAS, key)return result}// 返回一个由目标对象自身的属性键组成的数组function ownKeys(target: object): (string | number | symbol)[] {track(target, TrackOpTypes.ITERATE, ITERATE_KEY)return Reflect.ownKeys(target)}const hasOwnProperty = Object.prototype.hasOwnPropertyexport const hasOwn = (val: object,key: string | symbol): key is keyof typeof val => hasOwnProperty.call(val, key)
接下来再来看set get方法
set
const set = /*#__PURE__*/ createSetter()/*** @description: 拦截对象的设置属性操作* @param {shallow} 是否是浅观察*/function createSetter(shallow = false) {/*** @description:* @param {target} 目标对象* @param {key} 设置的属性的名称* @param {value} 要改变的属性值* @param {receiver} 如果遇到 setter,receiver则为setter调用时的this值*/return function set(target: object,key: string | symbol,value: unknown,receiver: object): boolean {const oldValue = (target as any)[key]// 如果模式不是浅观察if (!shallow) {value = toRaw(value)// 并且目标对象不是数组,旧值是ref,新值不是ref,则直接赋值,注意这里提到ref,这里不展开讲,后面详细讲if (!isArray(target) && isRef(oldValue) && !isRef(value)) {oldValue.value = valuereturn true}} else {// in shallow mode, objects are set as-is regardless of reactive or not}// 检查对象是否有这个属性const hadKey = hasOwn(target, key)// 赋值const result = Reflect.set(target, key, value, receiver)// don't trigger if target is something up in the prototype chain of originalif (target === toRaw(receiver)) {if (!hadKey) {// 如是不存在则trigger ADDtrigger(target, TriggerOpTypes.ADD, key, value)} else if (hasChanged(value, oldValue)) {// 存在则trigger SETtrigger(target, TriggerOpTypes.SET, key, value, oldValue)}}return result}}
get
const get = /*#__PURE__*/ createGetter()/*** @description: 用于拦截对象的读取属性操作* @param {isReadonly} 是否只读* @param {shallow} 是否浅观察*/function createGetter(isReadonly = false, shallow = false) {/*** @description:* @param {target} 目标对象* @param {key} 需要获取的值的键值* @param {receiver} 如果遇到 setter,receiver则为setter调用时的this值*/return function get(target: object, key: string | symbol, receiver: object) {// ReactiveFlags 是在reactive中声明的枚举值,如果key是枚举值则直接返回对应的布尔值if (key === ReactiveFlags.isReactive) {return !isReadonly} else if (key === ReactiveFlags.isReadonly) {return isReadonly} else if (key === ReactiveFlags.raw) { // 如果key是raw 则直接返回目标对象return target}const targetIsArray = isArray(target)// 如果目标对象是数组并且 key 属于三个方法之一 ['includes', 'indexOf', 'lastIndexOf'],即触发了这三个操作之一if (targetIsArray && hasOwn(arrayInstrumentations, key)) {return Reflect.get(arrayInstrumentations, key, receiver)}const res = Reflect.get(target, key, receiver)// 如果 key 是 symbol 内置方法,或者访问的是原型对象,直接返回结果,不收集依赖if (isSymbol(key) && builtInSymbols.has(key) || key === '__proto__') {return res}// 如果是浅观察并且不为只读则调用 track Get, 并返回结果if (shallow) {!isReadonly && track(target, TrackOpTypes.GET, key)return res}// 如果get的结果是refif (isRef(res)) {// 目标对象为数组并且不为只读调用 track Get, 并返回结果if (targetIsArray) {!isReadonly && track(target, TrackOpTypes.GET, key)return res} else {// ref unwrapping, only for Objects, not for Arrays.return res.value}}// 目标对象不为只读则调用 track Get!isReadonly && track(target, TrackOpTypes.GET, key)// 由于 proxy 只能代理一层,所以 target[key] 的值如果是对象,就继续对其进行代理return isObject(res)? isReadonly? // need to lazy access readonly and reactive here to avoid// circular dependencyreadonly(res): reactive(res): res}}const arrayInstrumentations: Record<string, Function> = {};['includes', 'indexOf', 'lastIndexOf'].forEach(key => {arrayInstrumentations[key] = function(...args: any[]): any {const arr = toRaw(this) as anyfor (let i = 0, l = (this as any).length; i < l; i++) {track(arr, TrackOpTypes.GET, i + '')}// we run the method using the original args first (which may be reactive)const res = arr[key](...args)if (res === -1 || res === false) {// if that didn't work, run it again using raw values.return arr[key](...args.map(toRaw))} else {return res}}})
结语
到这里 baseHandlers 整个就差不多就讲完,我们会发现里面频繁的调用的几个函数
- track 依赖收集
- trigger 触发依赖
这两个函数为 effect 里的方法,effect 为 reactive 的核心, 详情可以点这里
