BaseHandlers

这里照顾一下新同学,科普一下 handler,音译为处理器,我们也可以理解为处理器,在Proxy这篇文章中我们了解到 Proxy(target, handlers) 接收两个参数,target 为目标对象,handlers 就是针对我们对 target 操作的一系列行为同时做一些处理

正文

basehandlers 中包含了四种 handler

  • mutableHandlers 可变处理
  • readonlyHandlers 只读处理
  • shallowReactiveHandlers 浅观察处理(只观察目标对象的第一层属性)
  • shallowReadonlyHandlers 浅观察 && 只读处理

其中 readonlyHandlers shallowReactiveHandlers shallowReadonlyHandlers 都是 mutableHandlers 的变形版本,这里我们主要针对 mutableHandlers 展开

mutableHandlers

我们还是选择从定义看起

  1. export const mutableHandlers: ProxyHandler<object> = {
  2. get, // 用于拦截对象的读取属性操作
  3. set, // 用于拦截对象的设置属性操作
  4. deleteProperty, // 用于拦截对象的删除属性操作
  5. has, // 检查一个对象是否拥有某个属性
  6. ownKeys // 针对 getOwnPropertyNames, getOwnPropertySymbols, keys 的代理方法
  7. }

get set 代码量稍微多点,我们先来点轻松的

  1. /**
  2. * @description: 用于拦截对象的删除属性操作
  3. * @param {target} 目标对象
  4. * @param {key} 键值
  5. * @return {Boolean}
  6. */
  7. function deleteProperty(target: object, key: string | symbol): boolean {
  8. // hasOwn 的实现放下方了,检查一个对象是否包含当前key
  9. const hadKey = hasOwn(target, key)
  10. const oldValue = (target as any)[key]
  11. // Reflect 作用在于完成目标对象的默认,这里即指删除
  12. const result = Reflect.deleteProperty(target, key)
  13. // 如果该值被成功删除则调用 trigger,
  14. // trigger 为 effect 里的方法,effect 为 reactive 的核心, 后面会讲到
  15. if (result && hadKey) {
  16. trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue)
  17. }
  18. return result
  19. }
  20. /**
  21. * @description: 检查一个对象是否拥有某个属性
  22. * @param {target} 目标对象
  23. * @param {key} 键值
  24. * @return {Boolean}
  25. */
  26. function has(target: object, key: string | symbol): boolean {
  27. const result = Reflect.has(target, key)
  28. // track 也为 effect 里的方法,effect 为 reactive 的核心, 后面会讲到
  29. track(target, TrackOpTypes.HAS, key)
  30. return result
  31. }
  32. // 返回一个由目标对象自身的属性键组成的数组
  33. function ownKeys(target: object): (string | number | symbol)[] {
  34. track(target, TrackOpTypes.ITERATE, ITERATE_KEY)
  35. return Reflect.ownKeys(target)
  36. }
  37. const hasOwnProperty = Object.prototype.hasOwnProperty
  38. export const hasOwn = (
  39. val: object,
  40. key: string | symbol
  41. ): key is keyof typeof val => hasOwnProperty.call(val, key)

接下来再来看set get方法

  • set
  1. const set = /*#__PURE__*/ createSetter()
  2. /**
  3. * @description: 拦截对象的设置属性操作
  4. * @param {shallow} 是否是浅观察
  5. */
  6. function createSetter(shallow = false) {
  7. /**
  8. * @description:
  9. * @param {target} 目标对象
  10. * @param {key} 设置的属性的名称
  11. * @param {value} 要改变的属性值
  12. * @param {receiver} 如果遇到 setter,receiver则为setter调用时的this值
  13. */
  14. return function set(
  15. target: object,
  16. key: string | symbol,
  17. value: unknown,
  18. receiver: object
  19. ): boolean {
  20. const oldValue = (target as any)[key]
  21. // 如果模式不是浅观察
  22. if (!shallow) {
  23. value = toRaw(value)
  24. // 并且目标对象不是数组,旧值是ref,新值不是ref,则直接赋值,注意这里提到ref,这里不展开讲,后面详细讲
  25. if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
  26. oldValue.value = value
  27. return true
  28. }
  29. } else {
  30. // in shallow mode, objects are set as-is regardless of reactive or not
  31. }
  32. // 检查对象是否有这个属性
  33. const hadKey = hasOwn(target, key)
  34. // 赋值
  35. const result = Reflect.set(target, key, value, receiver)
  36. // don't trigger if target is something up in the prototype chain of original
  37. if (target === toRaw(receiver)) {
  38. if (!hadKey) {
  39. // 如是不存在则trigger ADD
  40. trigger(target, TriggerOpTypes.ADD, key, value)
  41. } else if (hasChanged(value, oldValue)) {
  42. // 存在则trigger SET
  43. trigger(target, TriggerOpTypes.SET, key, value, oldValue)
  44. }
  45. }
  46. return result
  47. }
  48. }
  • get
  1. const get = /*#__PURE__*/ createGetter()
  2. /**
  3. * @description: 用于拦截对象的读取属性操作
  4. * @param {isReadonly} 是否只读
  5. * @param {shallow} 是否浅观察
  6. */
  7. function createGetter(isReadonly = false, shallow = false) {
  8. /**
  9. * @description:
  10. * @param {target} 目标对象
  11. * @param {key} 需要获取的值的键值
  12. * @param {receiver} 如果遇到 setter,receiver则为setter调用时的this值
  13. */
  14. return function get(target: object, key: string | symbol, receiver: object) {
  15. // ReactiveFlags 是在reactive中声明的枚举值,如果key是枚举值则直接返回对应的布尔值
  16. if (key === ReactiveFlags.isReactive) {
  17. return !isReadonly
  18. } else if (key === ReactiveFlags.isReadonly) {
  19. return isReadonly
  20. } else if (key === ReactiveFlags.raw) { // 如果key是raw 则直接返回目标对象
  21. return target
  22. }
  23. const targetIsArray = isArray(target)
  24. // 如果目标对象是数组并且 key 属于三个方法之一 ['includes', 'indexOf', 'lastIndexOf'],即触发了这三个操作之一
  25. if (targetIsArray && hasOwn(arrayInstrumentations, key)) {
  26. return Reflect.get(arrayInstrumentations, key, receiver)
  27. }
  28. const res = Reflect.get(target, key, receiver)
  29. // 如果 key 是 symbol 内置方法,或者访问的是原型对象,直接返回结果,不收集依赖
  30. if (isSymbol(key) && builtInSymbols.has(key) || key === '__proto__') {
  31. return res
  32. }
  33. // 如果是浅观察并且不为只读则调用 track Get, 并返回结果
  34. if (shallow) {
  35. !isReadonly && track(target, TrackOpTypes.GET, key)
  36. return res
  37. }
  38. // 如果get的结果是ref
  39. if (isRef(res)) {
  40. // 目标对象为数组并且不为只读调用 track Get, 并返回结果
  41. if (targetIsArray) {
  42. !isReadonly && track(target, TrackOpTypes.GET, key)
  43. return res
  44. } else {
  45. // ref unwrapping, only for Objects, not for Arrays.
  46. return res.value
  47. }
  48. }
  49. // 目标对象不为只读则调用 track Get
  50. !isReadonly && track(target, TrackOpTypes.GET, key)
  51. // 由于 proxy 只能代理一层,所以 target[key] 的值如果是对象,就继续对其进行代理
  52. return isObject(res)
  53. ? isReadonly
  54. ? // need to lazy access readonly and reactive here to avoid
  55. // circular dependency
  56. readonly(res)
  57. : reactive(res)
  58. : res
  59. }
  60. }
  61. const arrayInstrumentations: Record<string, Function> = {}
  62. ;['includes', 'indexOf', 'lastIndexOf'].forEach(key => {
  63. arrayInstrumentations[key] = function(...args: any[]): any {
  64. const arr = toRaw(this) as any
  65. for (let i = 0, l = (this as any).length; i < l; i++) {
  66. track(arr, TrackOpTypes.GET, i + '')
  67. }
  68. // we run the method using the original args first (which may be reactive)
  69. const res = arr[key](...args)
  70. if (res === -1 || res === false) {
  71. // if that didn't work, run it again using raw values.
  72. return arr[key](...args.map(toRaw))
  73. } else {
  74. return res
  75. }
  76. }
  77. })

结语

到这里 baseHandlers 整个就差不多就讲完,我们会发现里面频繁的调用的几个函数

  • track 依赖收集
  • trigger 触发依赖

这两个函数为 effect 里的方法,effectreactive 的核心, 详情可以点这里