亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

目錄
1. 問題背景:set訪問器的局限性
2. 解決方案:利用 Proxy 攔截數(shù)組變動
2.1 Proxy 的實現(xiàn)
2.2 代碼解析
2.3 使用示例
3. 注意事項與總結
首頁 web前端 js教程 JavaScript類中數(shù)組屬性變動的監(jiān)聽與處理:Proxy深度解析

JavaScript類中數(shù)組屬性變動的監(jiān)聽與處理:Proxy深度解析

Oct 16, 2025 am 10:03 AM

JavaScript類中數(shù)組屬性變動的監(jiān)聽與處理:Proxy深度解析

當JavaScript類中的數(shù)組屬性通過push等方法進行修改時,其set訪問器不會被觸發(fā),導致無法有效監(jiān)聽數(shù)組內(nèi)部的變動。本文將詳細介紹如何利用JavaScript Proxy對象來解決這一問題,通過攔截數(shù)組的set操作,特別是對length屬性的修改,實現(xiàn)對數(shù)組變動的精確監(jiān)聽,并執(zhí)行如更新sessionStorage等額外任務,從而構建響應式的類屬性。

1. 問題背景:set訪問器的局限性

在JavaScript中,我們經(jīng)常使用getter和setter來控制類屬性的訪問和修改。例如,我們可能希望在每次設置一個屬性時執(zhí)行一些副作用,比如持久化到sessionStorage。然而,當這個屬性是一個數(shù)組時,直接對數(shù)組進行變異操作(如push、pop、splice等)并不會觸發(fā)該屬性的set訪問器。

考慮以下示例代碼:

class Environment {
  constructor() {
    this._crumbs = []; // 內(nèi)部存儲
  }

  set crumbs(value) {
    // 只有在直接賦值時才會觸發(fā),如 env.crumbs = [...]
    // 對 env.crumbs.push() 不會觸發(fā)
    sessionStorage.setItem('_crumbs', JSON.stringify(value));
    this._crumbs = value;
  }

  get crumbs() {
    // 從 sessionStorage 獲取或初始化
    if (sessionStorage.getItem('_crumbs') !== null) {
      this._crumbs = JSON.parse(sessionStorage.getItem('_crumbs'));
    } else {
      sessionStorage.setItem('_crumbs', JSON.stringify([]));
      this._crumbs = [];
    }
    return this._crumbs;
  }
}

let env = new Environment();
let crumb = { MetricId: 6, Concept: 'Back orders' };

env.crumbs.push(crumb); // ?? 這不會觸發(fā) crumbs 的 set 訪問器!
console.log(sessionStorage.getItem('_crumbs')); // 仍然是 "[]" 或舊值

上述代碼中,env.crumbs.push(crumb) 操作直接修改了_crumbs數(shù)組的引用內(nèi)容,但并沒有改變env.crumbs屬性本身的引用。因此,set crumbs(value) 方法不會被調(diào)用,導致sessionStorage未能及時更新。

2. 解決方案:利用 Proxy 攔截數(shù)組變動

為了解決set訪問器的局限性,我們可以使用JavaScript的Proxy對象。Proxy允許我們創(chuàng)建一個對象的代理,并攔截對該對象的基本操作,包括屬性讀取、寫入、函數(shù)調(diào)用等。通過攔截數(shù)組的set操作,我們可以精確地捕獲數(shù)組的變動。

核心思路是:將類屬性設置為一個Proxy對象,該Proxy代理一個內(nèi)部的數(shù)組。當對Proxy對象進行操作時,我們可以定義一個handler來攔截這些操作。對于數(shù)組的變異方法,大多數(shù)都會最終導致數(shù)組的length屬性發(fā)生變化。因此,我們可以監(jiān)聽length屬性的set操作,并在此時執(zhí)行我們的額外任務。

2.1 Proxy 的實現(xiàn)

以下是使用Proxy改進Environment類的示例:

class Environment {
  constructor() {
    // 1. 從 sessionStorage 加載或初始化內(nèi)部數(shù)組
    // crumbList 將作為 Proxy 的目標對象
    const crumbList =
      JSON.parse(sessionStorage.getItem('crumbs') ?? null) ?? [];

    // 2. 創(chuàng)建一個 Proxy 對象來代理 crumbList
    this.crumbs = new Proxy(crumbList, {
      /**
       * 攔截對代理對象的屬性設置操作
       * @param {Array} obj 目標對象 (crumbList)
       * @param {string|symbol} prop 正在設置的屬性名
       * @param {*} value 正在設置的屬性值
       * @returns {boolean} 表示設置操作是否成功
       */
      set(obj, prop, value) {
        // ?? 優(yōu)先執(zhí)行原始的設置操作,確保數(shù)組行為正常
        const result = Reflect.set(obj, prop, value);

        // 3. 關鍵:當 length 屬性被修改時,意味著數(shù)組發(fā)生了變動
        // 大多數(shù)數(shù)組變異方法(push, pop, splice, unshift, shift等)
        // 都會最終導致 length 屬性的變化。
        if (prop === 'length') {
          // 4. 在數(shù)組變動后,立即更新 sessionStorage
          sessionStorage.setItem('crumbs', JSON.stringify(crumbList));
        }
        return result;
      }
    });

    // 5. 為代理對象添加 valueOf 方法,返回數(shù)組的淺拷貝
    // 這在某些場景下(如需要一個純粹的數(shù)組副本)非常有用
    Object.defineProperty(this.crumbs, 'valueOf', {
      value: function valueOf() {
        return [...crumbList]; // 返回內(nèi)部數(shù)組的淺拷貝
      },
      configurable: true,
      writable: true
    });
  }
}

2.2 代碼解析

  1. 內(nèi)部數(shù)組 crumbList: 我們首先初始化一個內(nèi)部數(shù)組 crumbList。它會從 sessionStorage 加載現(xiàn)有數(shù)據(jù),如果沒有則為空數(shù)組。這個 crumbList 將是 Proxy 的真正目標對象。
  2. 創(chuàng)建 Proxy: this.crumbs = new Proxy(crumbList, { ... }) 創(chuàng)建了一個 Proxy 對象,它將作為 Environment 實例的 crumbs 屬性。所有對 this.crumbs 的操作都會被 Proxy 攔截。
  3. set 陷阱 (Trap): set(obj, prop, value) 是 Proxy 的一個陷阱,用于攔截對屬性的設置操作。
    • Reflect.set(obj, prop, value):這是非常重要的一步。它確保了原始的設置操作(例如,將新元素添加到 crumbList 或修改 length)能夠正常執(zhí)行。Reflect API 提供了與 Proxy 陷阱對應的默認行為。
    • if (prop === 'length'): 這是我們監(jiān)聽數(shù)組變動的核心邏輯。當數(shù)組的 length 屬性被修改時,意味著數(shù)組的內(nèi)容發(fā)生了增加或刪除。push、pop、shift、unshift、splice 等方法都會導致 length 的變化。
    • sessionStorage.setItem('crumbs', JSON.stringify(crumbList)): 在檢測到 length 變化后,我們將最新的 crumbList 內(nèi)容序列化并存儲到 sessionStorage。
  4. valueOf 方法: Object.defineProperty(this.crumbs, 'valueOf', ...) 為 Proxy 對象添加了一個 valueOf 方法。當需要獲取 crumbs 屬性的原始數(shù)組副本時,可以調(diào)用 env.crumbs.valueOf()。這可以防止直接返回 crumbList 導致外部代碼直接修改內(nèi)部狀態(tài)。

2.3 使用示例

現(xiàn)在,當我們對 env.crumbs 進行數(shù)組變異操作時,sessionStorage 將會自動更新:

const env = new Environment();

const metricId = 6;
const concept = 'Back orders';

const crumb = { metricId, concept };

// 1. push 操作
env.crumbs.push(crumb);
env.crumbs.push('foo');
console.log("After push:", env.crumbs.valueOf());
console.log("sessionStorage:", sessionStorage.getItem('crumbs'));
// 預期 sessionStorage 包含 [crumb, 'foo']

// 2. 直接修改 length
env.crumbs.length = 5; // 即使數(shù)組元素不足5個,也會觸發(fā) length 變化
env.crumbs.push('bar');
console.log("After length change and push:", env.crumbs.valueOf());
console.log("sessionStorage:", sessionStorage.getItem('crumbs'));
// 預期 sessionStorage 包含 [crumb, 'foo', undefined, undefined, 'bar']

// 3. shift 和 pop 操作
env.crumbs.shift();
env.crumbs.pop();
console.log("After shift and pop:", env.crumbs.valueOf());
console.log("sessionStorage:", sessionStorage.getItem('crumbs'));
// 預期 sessionStorage 相應更新

// 4. splice 操作
env.crumbs.splice(0, 1, 'new item');
console.log("After splice:", env.crumbs.valueOf());
console.log("sessionStorage:", sessionStorage.getItem('crumbs'));
// 預期 sessionStorage 相應更新

console.log({ "currently stored JSON": sessionStorage.getItem('crumbs') });

3. 注意事項與總結

  • length 屬性的可靠性: 監(jiān)聽 length 屬性的 set 陷阱是捕獲大多數(shù)數(shù)組變異操作(如 push, pop, shift, unshift, splice, sort, reverse 等)的有效方式,因為這些操作都會導致 length 發(fā)生變化。
  • 深層嵌套對象: 如果數(shù)組中包含對象,并且你希望監(jiān)聽這些對象的內(nèi)部屬性變動,那么你需要對數(shù)組中的每個對象也進行 Proxy 包裝,或者采用其他深度監(jiān)聽策略。本方案主要針對數(shù)組本身的結構變動。
  • 性能考量: Proxy 會引入一定的性能開銷,但對于大多數(shù)應用場景來說,這種開銷是微不足道的。
  • Reflect API: Reflect API 提供了與 Proxy 陷阱對應的默認操作,使用 Reflect.set 能夠確保在執(zhí)行自定義邏輯的同時,不影響原始操作的正確性。
  • valueOf 的作用: 通過提供 valueOf 方法返回數(shù)組的淺拷貝,可以避免外部代碼直接獲取并修改 Proxy 內(nèi)部的 crumbList 數(shù)組,從而保持內(nèi)部狀態(tài)的封裝性。

通過 Proxy,我們能夠為類中的數(shù)組屬性添加強大的響應式能力,使其在發(fā)生變動時能夠自動執(zhí)行自定義邏輯,這對于構建數(shù)據(jù)持久化、UI更新等功能非常有用。這種模式比手動調(diào)用更新函數(shù)更加優(yōu)雅和健壯。

以上是JavaScript類中數(shù)組屬性變動的監(jiān)聽與處理:Proxy深度解析的詳細內(nèi)容。更多信息請關注PHP中文網(wǎng)其他相關文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻,版權歸原作者所有,本站不承擔相應法律責任。如您發(fā)現(xiàn)有涉嫌抄襲侵權的內(nèi)容,請聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動的應用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Stock Market GPT

Stock Market GPT

人工智能驅(qū)動投資研究,做出更明智的決策

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級代碼編輯軟件(SublimeText3)

熱門話題

JavaScript實現(xiàn)點擊圖片切換效果:專業(yè)教程 JavaScript實現(xiàn)點擊圖片切換效果:專業(yè)教程 Sep 18, 2025 pm 01:03 PM

本文將介紹如何使用JavaScript實現(xiàn)點擊圖片切換的效果。核心思路是利用HTML5的data-*屬性存儲備用圖片路徑,并通過JavaScript監(jiān)聽點擊事件,動態(tài)切換src屬性,從而實現(xiàn)圖片切換。本文將提供詳細的代碼示例和解釋,幫助你理解和掌握這種常用的交互效果。

如何使用JavaScript中的GeOlocation API獲取用戶的位置? 如何使用JavaScript中的GeOlocation API獲取用戶的位置? Sep 21, 2025 am 06:19 AM

首先檢查瀏覽器是否支持GeolocationAPI,若支持則調(diào)用getCurrentPosition()獲取用戶當前位置坐標,并通過成功回調(diào)獲取緯度和經(jīng)度值,同時提供錯誤回調(diào)處理權限被拒、位置不可用或超時等異常,還可傳入配置選項以啟用高精度、設置超時時間和緩存有效期,整個過程需用戶授權并做好相應錯誤處理。

如何在JavaScript中使用setInterval創(chuàng)建重復間隔 如何在JavaScript中使用setInterval創(chuàng)建重復間隔 Sep 21, 2025 am 05:31 AM

要創(chuàng)建JavaScript中的重復間隔,需使用setInterval()函數(shù),它會以指定毫秒數(shù)為間隔重復執(zhí)行函數(shù)或代碼塊,例如setInterval(()=>{console.log("每2秒執(zhí)行一次");},2000)會每隔2秒輸出一次消息,直到通過clearInterval(intervalId)清除,實際應用中可用于更新時鐘、輪詢服務器等場景,但需注意最小延遲限制、函數(shù)執(zhí)行時間影響,并在不再需要時及時清除間隔以避免內(nèi)存泄漏,特別是在組件卸載或頁面關閉前應清理,確保

NUXT 3組成API解釋了 NUXT 3組成API解釋了 Sep 20, 2025 am 03:00 AM

Nuxt3的CompositionAPI核心用法包括:1.definePageMeta用于定義頁面元信息,如標題、布局和中間件,需在中直接調(diào)用,不可置于條件語句中;2.useHead用于管理頁面頭部標簽,支持靜態(tài)和響應式更新,需與definePageMeta配合實現(xiàn)SEO優(yōu)化;3.useAsyncData用于安全地獲取異步數(shù)據(jù),自動處理loading和error狀態(tài),支持服務端和客戶端數(shù)據(jù)獲取控制;4.useFetch是useAsyncData與$fetch的封裝,自動推斷請求key,避免重復請

JavaScript中數(shù)字格式化:使用toFixed()方法保留固定小數(shù)位 JavaScript中數(shù)字格式化:使用toFixed()方法保留固定小數(shù)位 Sep 16, 2025 am 11:57 AM

本教程詳細講解如何在JavaScript中將數(shù)字格式化為固定兩位小數(shù)的字符串,即使是整數(shù)也能顯示為"#.00"的形式。我們將重點介紹Number.prototype.toFixed()方法的使用,包括其語法、功能、示例代碼以及需要注意的關鍵點,如其返回類型始終為字符串。

如何將文本復制到JavaScript中的剪貼板? 如何將文本復制到JavaScript中的剪貼板? Sep 18, 2025 am 03:50 AM

使用ClipboardAPI的writeText方法可復制文本到剪貼板,需在安全上下文和用戶交互中調(diào)用,支持現(xiàn)代瀏覽器,舊版可用execCommand降級處理。

如何在JavaScript中創(chuàng)建多行字符串? 如何在JavaScript中創(chuàng)建多行字符串? Sep 20, 2025 am 06:11 AM

thebestatoreateamulti-linestlinginjavascriptsisisingsistisingtemplatalalswithbacktticks,whatpreserveticks,whatpreservereakeandeexactlyaswrite。

如何在JavaScript中創(chuàng)建和使用立即調(diào)用的函數(shù)表達式(IIFE) 如何在JavaScript中創(chuàng)建和使用立即調(diào)用的函數(shù)表達式(IIFE) Sep 21, 2025 am 05:04 AM

Aniife(立即InvokedFunction表達)IsafunctionThatrunSassoonAsisition定義,createByWrappingAppappingAptappafunctionInparenthensessandMmedImmedImmedInvokingit,whopreventsglobalnamespacepacepallutionpallutionpallutionPollutionPollutionPollutionAndEnablesPrivatesScopethroughCloseconscopethroughClosecome; itiswritten; itiswritten; itiswrittenas(iTiswrittenas;

See all articles