<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [vue3] Vue3源碼閱讀筆記 reactivity - baseHandlers

      源碼位置https://github.com/vuejs/core/blob/main/packages/reactivity/src/baseHandlers.ts

      baseHandler用于處理對象、數組類型的gettersetter

      這個文件中主要有兩個函數,和三個類。

      arrayInstrucmentationshasOwnProperty這兩個函數主要起到輔助作用;

      3個類:

      • BaseReactiveHandler:負責處理getter
      • MutableReactiveHandlerReadonlyReactiveHandler:負責處理setter
      graph LR A[ProxyHandler] --> B[BaseReactiveHandler] B --> C[MutableReactiveHandler] & D[ReadonlyReactiveHandler]

      依賴

      依賴比較零碎,大致分為以下幾種:

      1. 用于判斷數據類型;
      2. Vue內置的FlagType,用來標記對象或者操作的類型;
      3. 暫停與重置依賴追蹤和任務調度的方法;
      4. 其它零碎的比如:
        • warning:在控制臺輸出警告信息;
        • makeMap:傳入一個用,分隔的多個key組成的字符串,返回一個has函數用于檢查后續傳入的key是否存在于一開始傳入的字符串中。

      arrayInstrucmentations

      arrayInstrumentations這個對象用于記錄一些處理過的數組方法(攔截操作),通過createArrayInstrumentations構建后大概長這樣:

      {
          ...
          'push': function(this, ...args){...},
          'indexOf': function(this, ...args){...},
      	...
      }
      

      攔截這些方法的原因

      • ['includes', 'indexOf', 'lastIndexOf']:數組中可能包含響應式對象,這幾個方法是需要比較數組元素的,直接比較可能會出錯,因此需要攔截這些方法,在比較的過程中考慮使用toRaw轉成原始對象進行比較。

      • ['push', 'pop', 'shift', 'unshift', 'splice']:這些方法會改變數組的長度length屬性,從而觸發與length屬性相關的effect,而effect中如果又有這些方法,那么就會導致死循環。因此,這些方法需要被攔截做特殊處理,在執行這些方法的時候要暫停依賴的追蹤和調度。

        相關的issue是:fix(reactivity): some mutation methods of Array cause infinite recursion by unbyte · Pull Request #2138 · vuejs/core (github.com)

        image-20240730004826476

      源碼與注釋

      const arrayInstrumentations = /*#__PURE__*/ createArrayInstrumentations()
      
      function createArrayInstrumentations() {
        const instrumentations: Record<string, Function> = {}
      
        // 給需要處理可能包含響應式值的數組方法增加攔截邏輯
        ;(['includes', 'indexOf', 'lastIndexOf'] as const).forEach(key => {
          instrumentations[key] = function (this: unknown[], ...args: unknown[]) {
            // 將 this 轉換為原始數組
            const arr = toRaw(this) as any
            
            // 追蹤數組每個元素的 GET 操作
            for (let i = 0, l = this.length; i < l; i++) {
              track(arr, TrackOpTypes.GET, i + '')
            }
            
            // 先使用原始參數(可能是響應式的)運行原方法
            const res = arr[key](...args)
            
            // 如果結果是 -1 或 false,說明沒有找到或不匹配,再次使用原始值運行一次
            if (res === -1 || res === false) {
              return arr[key](...args.map(toRaw))
            } else {
              return res
            }
          }
        })
      
        // 攔截會改變數組長度的方法,避免長度變化被追蹤,從而防止出現無限循環的問題 (#2137)
        ;(['push', 'pop', 'shift', 'unshift', 'splice'] as const).forEach(key => {
          instrumentations[key] = function (this: unknown[], ...args: unknown[]) {
            // 暫停追蹤
            pauseTracking()
            // 暫停調度
            pauseScheduling()
            
            // 使用原始數組運行原方法
            const res = (toRaw(this) as any)[key].apply(this, args)
            
            // 重置調度
            resetScheduling()
            // 重置追蹤
            resetTracking()
            
            return res
          }
        })
        
        return instrumentations
      }
      
      

      hasOwnProperty

      Vue對hasOwnProperty做了特殊處理,主要在于處理以下問題:

      • 確保需要檢查的key只能是Symbol類型或string類型,如果是其它,則通過String()轉為字符串;
      • 使用toRaw在原始對象上查詢key是否存在;
      • 使用track追蹤key

      源碼

      function hasOwnProperty(this: object, key: unknown) {
        // #10455 hasOwnProperty may be called with non-string values
        if (!isSymbol(key)) key = String(key)
        const obj = toRaw(this)
        track(obj, TrackOpTypes.HAS, key)
        return obj.hasOwnProperty(key as string)
      }
      

      BaseReactiveHandler

      這個類主要負責配置getter,當reactiveAPI包裝的響應式對象的某個key被讀取時,會觸發這里的getter

      • 如果讀取的key是內置的ReactiveFlags,返回相應的值;
      • 如果target是一個數組,那么需要應用上述arrayInstrucmentations記錄的處理過的數組;
      • 如果keyhasOwnProperty,返回上述特殊處理過的hasOwnProperty
      • key記錄依賴。
      class BaseReactiveHandler implements ProxyHandler<Target> {
        constructor(
          protected readonly _isReadonly = false, // 是否只讀
          protected readonly _isShallow = false, // 是否淺層響應式
        ) {}
      
        get(target: Target, key: string | symbol, receiver: object) {
          const isReadonly = this._isReadonly,
            isShallow = this._isShallow
      
          // 處理 ReactiveFlags 特殊標志
          if (key === ReactiveFlags.IS_REACTIVE) {
            // 判斷目標是否是響應式的
            return !isReadonly
          } else if (key === ReactiveFlags.IS_READONLY) {
            // 判斷目標是否是只讀的
            return isReadonly
          } else if (key === ReactiveFlags.IS_SHALLOW) {
            // 判斷目標是否是淺層響應的
            return isShallow
          } else if (key === ReactiveFlags.RAW) {
            // 處理 RAW 標志
            if (
              receiver ===
                (isReadonly
                  ? isShallow
                    ? shallowReadonlyMap
                    : readonlyMap
                  : isShallow
                    ? shallowReactiveMap
                    : reactiveMap
                ).get(target) ||
              // receiver 不是響應式代理,但具有相同的原型
              // 這意味著 receiver 是響應式代理的用戶代理
              Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)
            ) {
              return target
            }
            // 提前返回 undefined
            return
          }
      
          const targetIsArray = isArray(target)
      
          // 處理非只讀的情況
          if (!isReadonly) {
            if (targetIsArray && hasOwn(arrayInstrumentations, key)) {
              // 對于數組的特殊方法,使用上述的方法攔截處理
              return Reflect.get(arrayInstrumentations, key, receiver)
            }
            if (key === 'hasOwnProperty') {
              // 特殊處理 hasOwnProperty 方法
              return hasOwnProperty
            }
          }
      
          // 默認的 Reflect.get 操作
          const res = Reflect.get(target, key, receiver)
      
          // 處理內置符號和非可追蹤的鍵
          if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {
            return res
          }
      
          // 處理非只讀情況,執行追蹤操作
          if (!isReadonly) {
            track(target, TrackOpTypes.GET, key)
          }
      
          // 處理淺層響應情況
          if (isShallow) {
            return res
          }
      
          // 處理 Ref 類型的值
          if (isRef(res)) {
            // 如果是數組并且鍵是整數,則跳過 unwrap
            return targetIsArray && isIntegerKey(key) ? res : res.value
          }
      
          // 處理對象類型的值,將返回的值轉化為代理對象
          if (isObject(res)) {
            // 將返回的值轉換為代理對象,避免循環依賴
            return isReadonly ? readonly(res) : reactive(res)
          }
      
          return res
        }
      }
      
      

      MutableReactiveHandler

      這個類實現了對setdeletePropertyhasownKeys的攔截

      class MutableReactiveHandler extends BaseReactiveHandler {
        constructor(isShallow = false) {
          super(false, isShallow) // 調用父類構造函數,設置只讀標志為 false
        }
      
        set(
          target: object,
          key: string | symbol,
          value: unknown,
          receiver: object,
        ): boolean {
          let oldValue = (target as any)[key] // 獲取目標對象中原有的值
          if (!this._isShallow) {
            // 如果不是淺層響應,進行深層處理
            const isOldValueReadonly = isReadonly(oldValue) // 判斷原有值是否是只讀的
            if (!isShallow(value) && !isReadonly(value)) {
              oldValue = toRaw(oldValue) // 獲取原有值的原始對象
              value = toRaw(value) // 獲取新值的原始對象
            }
            // 如果原有值是 ref 類型并且新值不是 ref 類型
            if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
              if (isOldValueReadonly) {
                // 如果原有值是只讀的,返回 false
                return false
              } else {
                oldValue.value = value // 更新 ref 的值
                return true
              }
            }
          } else {
            // 在淺層模式中,直接設置對象,不考慮其是否為響應式
          }
      
          // 判斷目標對象是否之前已經有這個鍵
          const hadKey =
            isArray(target) && isIntegerKey(key)
              ? Number(key) < target.length
              : hasOwn(target, key)
          const result = Reflect.set(target, key, value, receiver) // 使用 Reflect 設置值
          // 判斷target是否是實際被修改的對象
          if (target === toRaw(receiver)) {
            if (!hadKey) {
              // 如果之前沒有這個鍵,觸發 ADD 操作
              trigger(target, TriggerOpTypes.ADD, key, value)
            } else if (hasChanged(value, oldValue)) {
              // 如果鍵已經存在且新值不同,觸發 SET 操作
              trigger(target, TriggerOpTypes.SET, key, value, oldValue)
            }
          }
          return result
        }
      
        deleteProperty(target: object, key: string | symbol): boolean {
          const hadKey = hasOwn(target, key) // 判斷目標對象是否有這個鍵
          const oldValue = (target as any)[key] // 獲取原有值
          const result = Reflect.deleteProperty(target, key) // 使用 Reflect 刪除屬性
          if (result && hadKey) {
            // 如果刪除成功且目標對象之前有這個鍵,觸發 DELETE 操作
            trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue)
          }
          return result
        }
      
        has(target: object, key: string | symbol): boolean {
          const result = Reflect.has(target, key) // 使用 Reflect 檢查是否存在該鍵
          if (!isSymbol(key) || !builtInSymbols.has(key)) {
            // 如果鍵不是內置符號,追蹤 HAS 操作
            track(target, TrackOpTypes.HAS, key)
          }
          return result
        }
      
        ownKeys(target: object): (string | symbol)[] {
          // 追蹤 ITERATE 操作,用于獲取對象的所有鍵
          track(
            target,
            TrackOpTypes.ITERATE,
            isArray(target) ? 'length' : ITERATE_KEY,
          )
          return Reflect.ownKeys(target) // 使用 Reflect 獲取對象的所有鍵
        }
      }
      
      

      解析set里的trigger時機:

      // 判斷target是否是實際被修改的對象
      if (target === toRaw(receiver)) {
        if (!hadKey) {
          // 如果之前沒有這個鍵,觸發 ADD 操作
          trigger(target, TriggerOpTypes.ADD, key, value)
        } else if (hasChanged(value, oldValue)) {
          // 如果鍵已經存在且新值不同,觸發 SET 操作
          trigger(target, TriggerOpTypes.SET, key, value, oldValue)
        }
      }
      

      如果target !== toRaw(receiver)說明此時不是在對象上修改它本身的屬性,而是通過原型鏈上的其它對象。這種情況不會觸發更新。

      ReadonlyReactiveHandler

      這個類比較簡單,主要是攔截setdeleteProperty這兩個會改變對象的操作。

      開發模式下會在控制臺輸出警告。

      注意setdeleteProperty操作會返回true,這是為了符合Proxy規范:即使某些操作被攔截并不實際改變對象的狀態,仍然需要返回一個布爾值以指示操作的成功或失敗。

      class ReadonlyReactiveHandler extends BaseReactiveHandler {
        constructor(isShallow = false) {
          super(true, isShallow) // 調用父類構造函數,將 isReadonly 設置為 true,表示對象是只讀的
        }
      
        set(target: object, key: string | symbol, value: unknown): boolean {
          if (__DEV__) {
            warn(
              `Set operation on key "${String(key)}" failed: target is readonly.`,
              target,
            )
          }
          return true // 返回 true,表示設置操作被忽略
        }
      
        deleteProperty(target: object, key: string | symbol): boolean {
          if (__DEV__) {
            warn(
              `Delete operation on key "${String(key)}" failed: target is readonly.`,
              target,
            )
          }
          return true // 返回 true,表示刪除操作被忽略
        }
      }
      
      
      posted @ 2024-07-30 03:00  feixianxing  閱讀(76)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产成人精品中文字幕| 97亚洲熟妇自偷自拍另类图片 | 99在线 | 亚洲| 人人妻人人狠人人爽天天综合网| 国色天香中文字幕在线视频 | 亚洲av日韩av综合在线观看| 国产suv精品一区二区883| 九九热爱视频精品视频| 精品国产综合一区二区三区| 国产91精品丝袜美腿在线| 欧洲精品色在线观看| 苍井空一区二区三区在线观看| 九九在线精品国产| 欧美丰满熟妇xxxx性| 亚洲韩国精品无码一区二区三区| 国产午夜亚洲精品不卡网站| 特黄aaaaaaaaa毛片免费视频| 日本道高清一区二区三区| 在线a级毛片无码免费真人| 人妻人人做人碰人人添| 国产区精品视频自产自拍| 无套内谢极品少妇视频| 婷婷成人丁香五月综合激情| 四虎永久在线精品免费看| 精品国产精品中文字幕| 99久久国产宗和精品1上映| 国产精品老熟女乱一区二区| 国产首页一区二区不卡| 国产又黄又硬又粗| 亚洲熟女一区二区av| 亚洲色大成网站WWW永久麻豆| 富宁县| 久久综合开心激情五月天| 男同精品视频免费观看网站| 1精品啪国产在线观看免费牛牛| 亚洲精品成人福利网站| 中文字幕免费不卡二区| 亚洲免费成人av一区| 精品国产中文字幕懂色| 黑人巨大亚洲一区二区久| 亚洲欧美成人久久综合中文网|