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

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

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

      【每日一面】你怎么理解 Proxy 的

      基礎問答

      問:Proxy 是什么?怎么使用的?

      答:Proxy 是用于創建 “對象代理” 的構造函數,它能封裝目標對象(target),并通過 “攔截器對象(handler)” 自定義目標對象的基礎操作(如屬性讀取、賦值),實現對對象行為的 “劫持”,手寫使用方式。

      // 語法:new Proxy(target, handler)
      // 參數:target-目標對象,handler-攔截器對象
      // 返回值:代理實例proxy
      
      const target = { name: '前端面試', age: 2 };
      // 定義攔截器對象
      const handler = {
        // 攔截“讀取屬性”操作:參數為target(目標對象)、prop(屬性名)、receiver(代理實例)
        get(target, prop, receiver) {
          console.log(`觸發get攔截:讀取屬性${prop}`);
          // 執行原始讀取操作(通過Reflect確保this指向正確)
          return Reflect.get(target, prop, receiver);
        },
      
        // 攔截“賦值屬性”操作:參數為target、prop、value(新值)、receiver
        set(target, prop, value, receiver) {
          console.log(`觸發set攔截:給屬性${prop}賦值${value}`);
          // 自定義邏輯:校驗age屬性必須為數字
          if (prop === 'age' && typeof value !== 'number') {
            throw new Error('age屬性必須是數字');
          }
          // 執行原始賦值操作
          return Reflect.set(target, prop, value, receiver);
        }
      };
      
      // 創建代理實例
      const proxy = new Proxy(target, handler);
      
      // 操作代理實例,觸發攔截
      console.log(proxy.name); // 輸出:觸發get攔截:讀取屬性name → 前端面試
      proxy.age = 3; // 輸出:觸發set攔截:給屬性age賦值3 → 成功
      proxy.age = '3'; // 輸出:觸發set攔截:給屬性age賦值3 → 拋出錯誤:age屬性必須是數字
      
      // 直接操作目標對象,不會觸發攔截
      console.log(target.name); // 輸出:前端面試(無攔截日志)
      target.age = '4'; // 無攔截日志,且不會觸發age的類型校驗
      

      擴展延伸

      Proxy API 的核心三要素是:“目標對象(target)”“攔截器對象(handler)”“代理實例(proxy)”。

      • 目標對象(target):被代理的原始對象(可以是對象、數組、函數,甚至另一個 Proxy 實例);
      • 攔截器(handler):包含 “攔截方法” 的對象,每個攔截方法對應一種目標對象的基礎操作(如get攔截屬性讀取,set攔截屬性賦值);
      • 代理實例(proxy):通過new Proxy(target, handler) 創建的代理對象,所有對目標對象的操作需通過代理實例完成,才能觸發攔截器。也就是說,直接操作目標對象,就不會走代理。

      Proxy 是一種非侵入性的 API,他不會修改目標對象本身的結構或方法,所有攔截邏輯都封裝在攔截器中,實現 “代理行為” 與 “目標對象” 的解耦,相對 Object.defineProperty 更加靈活。

      攔截器方法除了基礎的 get/set 方法,需要注意一些特殊的攔截方法(has/deleteProperty/apply/construct):

      攔截方法 作用 關鍵參數 適用場景
      get 攔截屬性讀取(含 obj.prop、obj [prop]) target, prop, receiver 數據劫持(如響應式)、默認值設置
      set 攔截屬性賦值 target, prop, value, receiver 數據校驗、值格式化
      has 攔截 in 運算符(如prop in proxy) target, prop 權限控制(隱藏某些屬性不被檢測)
      deleteProperty 攔截 delete 操作(如delete proxy.prop) target, prop 禁止刪除關鍵屬性
      apply 攔截函數調用(僅當 target 是函數時) target, thisArg, args 函數參數校驗、調用日志記錄
      construct 攔截 new 操作(僅當 target 是構造函數時) target, args, newTarget 構造函數參數校驗、實例計數

      如果你使用 Vue3 框架,需要知道的時 Vue3 的響應式設計就是基于 Proxy 的,這是一個簡化版的響應式 API 設計:

      // 存儲當前活躍的副作用函數(如組件渲染函數)
      let activeEffect = null;
      
      // 依賴映射表:target → { prop → [effect1, effect2,...] }
      const targetMap = new WeakMap();
      
      // 1. 依賴收集函數:將副作用函數與target、prop關聯
      function track(target, prop) {
        if (!activeEffect) return; // 無活躍副作用,不收集
        // 確保target在targetMap中存在映射
        let depsMap = targetMap.get(target);
        if (!depsMap) {
          depsMap = new Map();
          targetMap.set(target, depsMap);
        }
        // 確保prop在depsMap中存在副作用數組
        let deps = depsMap.get(prop);
        if (!deps) {
          deps = new Set(); // 用Set避免重復副作用
          depsMap.set(prop, deps);
        }
        // 添加當前副作用函數
        deps.add(activeEffect);
      }
      
      // 2. 依賴觸發函數:執行target、prop對應的所有副作用
      function trigger(target, prop) {
        const depsMap = targetMap.get(target);
        if (!depsMap) return;
        const deps = depsMap.get(prop);
        if (deps) {
          deps.forEach(effect => effect()); // 執行所有副作用
        }
      }
      
      // 3. 響應式函數:創建Proxy代理,實現依賴收集與觸發
      function reactive(target) {
        return new Proxy(target, {
          get(target, prop, receiver) {
            const value = Reflect.get(target, prop, receiver);
            track(target, prop); // 讀取時收集依賴
            // 若value是對象,遞歸創建響應式(深度響應)
            if (typeof value === 'object' && value !== null) {
              return reactive(value);
            }
            return value;
          },
          set(target, prop, value, receiver) {
            const oldValue = Reflect.get(target, prop, receiver);
            const success = Reflect.set(target, prop, value, receiver);
            if (success && oldValue !== value) {
              trigger(target, prop); // 賦值時觸發依賴
            }
            return success;
          }
        });
      }
      
      // 4. 副作用函數注冊:執行fn并收集其依賴
      function effect(fn) {
        activeEffect = fn;
        fn(); // 執行fn,觸發get攔截,收集依賴
        activeEffect = null; // 重置,避免后續誤收集
      }
      
      // 測試響應式
      const data = reactive({ count: 0 });
      // 注冊副作用函數(模擬組件渲染)
      effect(() => {
        console.log(`視圖更新:count = ${data.count}`);
      });
      
      // 修改數據,觸發副作用(視圖更新)
      data.count = 1; // 輸出:視圖更新:count = 1
      data.count = 2; // 輸出:視圖更新:count = 2
      

      面試追問

      1. Proxy 和 Object.defineProperty 都能實現數據劫持,為什么 Vue3 放棄 Object.defineProperty 改用 Proxy?兩者的核心差異是什么?
      對比維度 Object.defineProperty Proxy
      劫持范圍 僅能劫持 “對象的單個屬性”(需遍歷屬性逐個定義) 直接劫持 “整個對象”(無需遍歷屬性)
      數組支持 無法劫持數組的原生方法(如 push、splice),需重寫數組原型 能攔截數組的所有操作(包括索引賦值、原生方法調用)
      嵌套對象處理 需遞歸遍歷所有嵌套對象,手動為每個屬性定義劫持 可在 get 攔截中遞歸創建代理(按需劫持,性能更優)
      性能 初始化時需遍歷所有屬性,嵌套層級深時性能差 懶加載式劫持(訪問嵌套對象時才創建代理),初始化性能更優
      1. 用 Proxy 攔截對象屬性賦值時,若目標對象是凍結對象(Object.freeze),set 攔截器還能生效嗎?為什么?
        set 攔截器會觸發,但最終賦值會失敗,Object.freeze (target) 會讓目標對象的屬性變為 “不可寫、不可配置”,但不會阻止 Proxy 攔截器的觸發(攔截器是對操作的劫持,而非直接修改屬性)。

      2. 若用 Proxy 代理一個頻繁修改的大型對象(如包含 1000 個屬性的列表),會有性能問題嗎?如何優化?
        會有性能問題,需要從兩方面考慮:1. 若攔截器邏輯復雜(如每次 get/set 都執行大量校驗、日志記錄),頻繁操作時會累積性能損耗;2. 對嵌套層級極深的大型對象,若初始化時遞歸創建代理(而非按需劫持),會導致初始化耗時過長。
        優化方案:1. 簡化攔截器邏輯:將非必要操作(如詳細日志)改為條件觸發(如開發環境才執行),避免每次攔截都執行冗余代碼;2. 按需劫持(懶加載):僅在訪問嵌套對象時,才為其創建 Proxy(如 Vue3 的響應式實現),避免初始化時遞歸遍歷所有屬性;3. 跳過無意義攔截:對不需要劫持的屬性(如只讀屬性、常量),在攔截器中直接返回原始值,不執行額外邏輯;4. 使用 WeakMap 緩存代理實例:避免對同一目標對象重復創建 Proxy,減少內存占用與初始化開銷。

      posted @ 2025-10-30 11:51  Achieve前端實驗室  閱讀(236)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 欧美日韩一区二区三区视频播放| 国产强奷在线播放免费| 国产一区二区三区AV在线无码观看| 国产一区二区三区黄网| 精品人妻少妇一区二区三区在线| 水蜜桃av导航| 岛国岛国免费v片在线观看| 中文字幕久久人妻熟人妻| 久久这里都是精品一区| 国产伦精区二区三区视频| 国产成年码av片在线观看| AV免费播放一区二区三区| 中文字幕久久精品波多野结| 亚洲香蕉视频天天爽| 日韩一区二区三区水蜜桃| 强奷乱码欧妇女中文字幕熟女| 欧美激情一区二区久久久| 99精品国产在热久久婷婷| 中文字幕日韩精品人妻| 人妻在线无码一区二区三区| 国产情侣激情在线对白| 久久青青草原精品国产app| 亚洲伊人成无码综合网| 暖暖影院日本高清...免费| 99re6这里有精品热视频| 蜜臀av一区二区三区在线| 亚洲欧美在线看片AI| 昔阳县| 国产成人精品一区二区无| 免费AV片在线观看网址| 最近日本免费观看高清视频| 日本一区二区精品色超碰| 亚洲午夜无码久久久久蜜臀av| 麻豆一区二区中文字幕| 久久亚洲色www成人欧美| 国产欧美日韩精品第二区| 亚洲综合精品第一页| 中文字幕国产精品一区二| 国产18禁黄网站禁片免费视频| 青草热在线观看精品视频| 精品无人区一区二区三区在线|