最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

TypeScript 不可變性 readonly, Readonly<T>的使用小結(jié)

 更新時(shí)間:2026年05月13日 09:33:48   作者:哈希茶館  
TypeScript 作為 JavaScript 的超集,為我們提供了強(qiáng)大的類型系統(tǒng),其中就包括了實(shí)現(xiàn)不可變性的有效工具,今天,我們就來聊聊如何使用 readonly和 Readonly來提升代碼的健壯性和可維護(hù)性

哈嘍,大家好,歡迎來到【哈希茶館】!在日常的全棧開發(fā)中,我們經(jīng)常會(huì)遇到因數(shù)據(jù)被意外修改而導(dǎo)致的各種詭異 Bug。特別是在 JavaScript 這種動(dòng)態(tài)語言中,對(duì)象的屬性默認(rèn)是可變的,這在大型或多人協(xié)作的項(xiàng)目中很容易引入不確定性。TypeScript 作為 JavaScript 的超集,為我們提供了強(qiáng)大的類型系統(tǒng),其中就包括了實(shí)現(xiàn)不可變性的有效工具。今天,我們就來聊聊如何使用 readonlyReadonly<T> 來提升代碼的健壯性和可維護(hù)性。

什么是不可變性?為什么它很重要?

簡(jiǎn)單來說,不可變性(Immutability)指的是一個(gè)對(duì)象在創(chuàng)建之后,其狀態(tài)就不能再被修改。如果我們想改變這個(gè)對(duì)象,不能直接修改原始對(duì)象,而是應(yīng)該創(chuàng)建一個(gè)新的對(duì)象,這個(gè)新對(duì)象擁有修改后的狀態(tài)。

擁抱不可變性有諸多好處:

  1. 可預(yù)測(cè)性更高:當(dāng)你知道一個(gè)數(shù)據(jù)結(jié)構(gòu)不會(huì)被意外改變時(shí),代碼的行為就更容易預(yù)測(cè)和推理。
  2. 簡(jiǎn)化調(diào)試:如果應(yīng)用狀態(tài)是不可變的,追蹤狀態(tài)變更就變得簡(jiǎn)單,因?yàn)槊看巫兏紩?huì)產(chǎn)生新的對(duì)象。
  3. 性能優(yōu)化:在某些場(chǎng)景下(例如 React 的 PureComponent 或 Redux),通過比較對(duì)象的引用就能快速判斷數(shù)據(jù)是否發(fā)生變化,從而避免不必要的渲染或計(jì)算。
  4. 更易于并發(fā)處理:不可變數(shù)據(jù)天然線程安全,因?yàn)樗鼈儾粫?huì)被多個(gè)線程同時(shí)修改(雖然在前端 JavaScript 中并發(fā)場(chǎng)景相對(duì)較少,但這個(gè)理念依然重要)。

readonly修飾符:讓屬性只讀

TypeScript 提供了 readonly 修飾符,可以用來標(biāo)記類的屬性或接口的屬性,表示這些屬性在對(duì)象初始化之后就不能再被修改。

1. 類屬性的readonly

class UserProfile {
    readonly userId: string;
    name: string;

    constructor(userId: string, name: string) {
        this.userId = userId; // 可以在構(gòu)造函數(shù)中賦值
        this.name = name;
    }

    updateName(newName: string) {
        this.name = newName; // 普通屬性可以修改
    }

    // 嘗試修改 readonly 屬性會(huì)導(dǎo)致編譯錯(cuò)誤
    // updateUserId(newUserId: string) {
    //     this.userId = newUserId; // Error: Cannot assign to 'userId' because it is a read-only property.
    // }
}

const user = new UserProfile("user-123", "Alice");
console.log(user.userId); // "user-123"
user.updateName("Bob");
console.log(user.name); // "Bob"

// user.userId = "user-456"; // Error: Cannot assign to 'userId' because it is a read-only property.

在上面的例子中,userId 屬性被 readonly 修飾后,只能在構(gòu)造函數(shù) constructor 中被初始化。之后任何嘗試修改 userId 的行為都會(huì)在編譯階段被 TypeScript 編譯器捕獲并報(bào)錯(cuò)。

2. 接口屬性的readonly

readonly 同樣可以用于接口定義:

interface Point {
    readonly x: number;
    readonly y: number;
}

let p1: Point = { x: 10, y: 20 };
// p1.x = 5; // Error: Cannot assign to 'x' because it is a read-only property.

function movePoint(p: Point, dx: number, dy: number): Point {
    // 不能直接修改 p.x 和 p.y
    // 要返回一個(gè)新的 Point 對(duì)象
    return { x: p.x + dx, y: p.y + dy };
}

const p2 = movePoint(p1, 5, 5);
console.log(p1); // { x: 10, y: 20 } (原始對(duì)象未改變)
console.log(p2); // { x: 15, y: 25 } (返回了新對(duì)象)

這里,Point 接口的 xy 屬性都是只讀的。當(dāng)我們嘗試修改 p1.x 時(shí),編譯器會(huì)報(bào)錯(cuò)。movePoint 函數(shù)也遵循了不可變性的原則,它沒有修改傳入的 Point 對(duì)象,而是返回了一個(gè)全新的 Point 對(duì)象。

注意readonly 提供的是淺不可變性。如果 readonly 屬性本身是一個(gè)對(duì)象,那么這個(gè)對(duì)象的屬性仍然是可以修改的。

interface Config {
    readonly serverUrl: string;
    readonly settings: {
        timeout: number;
        retries: number;
    };
}

const appConfig: Config = {
    serverUrl: "https://api.example.com",
    settings: {
        timeout: 5000,
        retries: 3,
    },
};

// appConfig.serverUrl = "https://new.api.example.com"; // Error: Cannot assign to 'serverUrl' because it is a read-only property.

appConfig.settings.timeout = 10000; // 這是允許的!
console.log(appConfig.settings.timeout); // 10000

appConfig.settings 本身是 readonly 的,意味著你不能給 appConfig.settings 賦一個(gè)新的對(duì)象。但是 settings 對(duì)象內(nèi)部的 timeout 屬性依然是可變的。

Readonly<T>工具類型:創(chuàng)建全只讀類型

當(dāng)我們需要將一個(gè)現(xiàn)有類型的所有屬性都變成只讀時(shí),TypeScript 的 Readonly<T> 工具類型就派上用場(chǎng)了。它會(huì)構(gòu)造一個(gè)新類型,將類型 T 的所有屬性都設(shè)置為 readonly。

interface MutableConfigs {
    port: number;
    debugMode: boolean;
    features: string[];
}

// 使用 Readonly<T> 將 MutableConfigs 的所有屬性變?yōu)橹蛔x
type ImmutableConfigs = Readonly<MutableConfigs>;

const initialConfigs: MutableConfigs = {
    port: 3000,
    debugMode: true,
    features: ["featureA", "featureB"]
};

// immutableAppConfig 的類型是 ImmutableConfigs
const immutableAppConfig: ImmutableConfigs = initialConfigs;

// immutableAppConfig.port = 8080; // Error: Cannot assign to 'port' because it is a read-only property.
// immutableAppConfig.debugMode = false; // Error: Cannot assign to 'debugMode' because it is a read-only property.

// 同樣,Readonly<T> 也是淺不可變的
// immutableAppConfig.features.push("featureC"); // 這仍然是允許的,因?yàn)?features 是一個(gè)數(shù)組對(duì)象
// console.log(immutableAppConfig.features); // ["featureA", "featureB", "featureC"]

// 如果要使數(shù)組也只讀,可以這樣定義:
interface TrulyImmutableConfigs {
    readonly port: number;
    readonly debugMode: boolean;
    readonly features: ReadonlyArray<string>; // 使用 ReadonlyArray<T>
}

const trulyImmutableAppConfig: TrulyImmutableConfigs = {
    port: 8000,
    debugMode: false,
    features: ["logging", "monitoring"]
};

// trulyImmutableAppConfig.features.push("newFeature"); // Error: Property 'push' does not exist on type 'readonly string[]'.
// trulyImmutableAppConfig.features[0] = "newLogging"; // Error: Index signature in type 'readonly string[]' only permits reading.

Readonly<T> 非常適合用于函數(shù)參數(shù)或返回值,以明確表示函數(shù)不會(huì)(或不應(yīng)該)修改傳入的對(duì)象,或者返回一個(gè)不應(yīng)被修改的對(duì)象。

function processConfig(config: Readonly<MutableConfigs>): void {
    console.log(`Processing config for port: ${config.port}`);
    // config.port = 8081; // Error: Cannot assign to 'port' because it is a read-only property.
}

processConfig(initialConfigs);

ReadonlyArray<T>

對(duì)于數(shù)組,TypeScript 提供了 ReadonlyArray<T> 類型。一個(gè) ReadonlyArray<T> 移除了所有會(huì)修改數(shù)組的方法(如 push, pop, splice 等),并且其索引簽名也是只讀的,防止通過索引直接修改元素。

let readOnlyNumbers: ReadonlyArray<number> = [1, 2, 3, 4, 5];

// readOnlyNumbers.push(6); // Error: Property 'push' does not exist on type 'readonly number[]'.
// readOnlyNumbers[0] = 0; // Error: Index signature in type 'readonly number[]' only permits reading.

// 可以使用不會(huì)修改原數(shù)組的方法
const doubledNumbers = readOnlyNumbers.map(n => n * 2);
console.log(doubledNumbers); // [2, 4, 6, 8, 10]
console.log(readOnlyNumbers); // [1, 2, 3, 4, 5] (原始數(shù)組未改變)

實(shí)踐中的考量與深不可變性

readonlyReadonly<T> 為我們提供了在 TypeScript 中實(shí)現(xiàn)不可變性的基礎(chǔ)工具。它們主要提供的是淺不可變性。這意味著如果一個(gè)只讀屬性本身是一個(gè)復(fù)雜對(duì)象(如對(duì)象或數(shù)組),那么這個(gè)復(fù)雜對(duì)象的內(nèi)部屬性仍然是可變的。

要實(shí)現(xiàn)深不可變性(Deep Immutability),即對(duì)象及其所有嵌套的子對(duì)象都不可變,通常需要:

  1. 遞歸地定義只讀類型:手動(dòng)為嵌套結(jié)構(gòu)定義 readonly
  2. 使用第三方庫:像 Immer 或 Immutable.js 這樣的庫提供了更完善的深不可變數(shù)據(jù)結(jié)構(gòu)和操作方法。

在大多數(shù)日常開發(fā)場(chǎng)景中,TypeScript 內(nèi)建的淺不可變性已經(jīng)能解決很多問題,特別是在定義配置對(duì)象、函數(shù)契約等方面。當(dāng)處理復(fù)雜的狀態(tài)管理(如 Redux store)時(shí),可以考慮引入專門的不可變數(shù)據(jù)庫。

總結(jié)

擁抱不可變性是提升代碼質(zhì)量、減少 Bug、增強(qiáng)系統(tǒng)可維護(hù)性的重要手段。TypeScript 的 readonly 修飾符和 Readonly<T> 工具類型為我們提供了在編譯時(shí)強(qiáng)制實(shí)施不可變性的能力。

  • 使用 readonly 標(biāo)記那些初始化后不應(yīng)再改變的類屬性或接口屬性。
  • 使用 Readonly<T> 將現(xiàn)有類型的所有屬性轉(zhuǎn)換為只讀,常用于函數(shù)參數(shù)和返回值。
  • 對(duì)于數(shù)組,使用 ReadonlyArray<T> 來確保數(shù)組內(nèi)容不被修改。

雖然它們提供的是淺不可變性,但這已經(jīng)是向前邁出的一大步。養(yǎng)成使用這些工具的習(xí)慣,你的代碼會(huì)變得更加穩(wěn)健和可預(yù)測(cè)。

到此這篇關(guān)于TypeScript 不可變性 readonly, Readonly<T>的使用小結(jié)的文章就介紹到這了,更多相關(guān)TypeScript 不可變性 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 在HTML中引入JavaScript的三種方式及優(yōu)缺點(diǎn)詳解

    在HTML中引入JavaScript的三種方式及優(yōu)缺點(diǎn)詳解

    本文詳細(xì)介紹了HTML中引入JavaScript的三種方式,包括事件句柄的使用(如點(diǎn)擊事件觸發(fā)警告框)、腳本塊的編寫位置及其執(zhí)行順序,以及引入外部JS文件的實(shí)踐,需要的朋友可以參考下
    2026-02-02
  • js過濾HTML標(biāo)簽完整實(shí)例

    js過濾HTML標(biāo)簽完整實(shí)例

    這篇文章主要介紹了js過濾HTML標(biāo)簽實(shí)現(xiàn)方法,以完整實(shí)例形式分析了JavaScript使用正則表達(dá)式過濾HTML標(biāo)簽的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • Next.js?16的實(shí)踐案例和坑點(diǎn)總結(jié)

    Next.js?16的實(shí)踐案例和坑點(diǎn)總結(jié)

    Next.js16的到來,總體來說對(duì)Next.js開發(fā)者來說是好事,并且讓我看到了未來在技術(shù)選擇中,是否對(duì)AI友好將會(huì)成為關(guān)鍵點(diǎn),這篇文章主要介紹了Next.js?16實(shí)踐案例和坑點(diǎn)的相關(guān)資料,需要的朋友可以參考下
    2026-01-01
  • js使下拉列表框可編輯不止是選擇

    js使下拉列表框可編輯不止是選擇

    下拉列表框默認(rèn)情況下是不可編輯的,下面為大家介紹個(gè)不錯(cuò)的方法可以使下拉列表框可編輯,具體實(shí)現(xiàn)如下,需要的朋友可以參考下
    2013-12-12
  • JavaScript實(shí)現(xiàn)日期格式化的操作詳解

    JavaScript實(shí)現(xiàn)日期格式化的操作詳解

    在我們做業(yè)務(wù)開發(fā)的漫長(zhǎng)歲月里,會(huì)多次跟時(shí)間打交道,相信大多數(shù)小伙伴對(duì)日期格式化也并不陌生,本文簡(jiǎn)單記錄了JavaScript實(shí)現(xiàn)日期格式化的過程,以及一些拓展,希望對(duì)大家有所幫助
    2023-05-05
  • JavaScript圣杯布局與雙飛翼布局實(shí)現(xiàn)案例詳解

    JavaScript圣杯布局與雙飛翼布局實(shí)現(xiàn)案例詳解

    這篇文章主要介紹了JavaScript圣杯布局與雙飛翼布局實(shí)現(xiàn)案例,這是前端面試中需要掌握的知識(shí)點(diǎn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • 純JavaScript實(shí)現(xiàn)獲取onclick、onchange等事件的值

    純JavaScript實(shí)現(xiàn)獲取onclick、onchange等事件的值

    這篇文章主要介紹了JavaScript獲取onclick、onchange等事件的值的方法,需要的朋友可以參考下
    2014-12-12
  • JavaScript閉包和范圍實(shí)例詳解

    JavaScript閉包和范圍實(shí)例詳解

    這篇文章主要介紹了JavaScript閉包和范圍,結(jié)合實(shí)例形式詳細(xì)分析了javascript閉包的使用及變量的作用范圍,需要的朋友可以參考下
    2016-12-12
  • 使用webpack-dev-server處理跨域請(qǐng)求的方法

    使用webpack-dev-server處理跨域請(qǐng)求的方法

    本篇文章主要介紹了使用webpack-dev-server處理跨域請(qǐng)求的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • layui prompt 設(shè)置允許空白提交的方法

    layui prompt 設(shè)置允許空白提交的方法

    今天小編就為大家分享一篇layui prompt 設(shè)置允許空白提交的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09

最新評(píng)論

宝坻区| 本溪| 石景山区| 清丰县| 伊春市| 上饶县| 东平县| 孙吴县| 邯郸市| 嵩明县| 策勒县| 江陵县| 吴桥县| 叙永县| 柘荣县| 新疆| 金华市| 昌黎县| 湛江市| 宝清县| 宣威市| 文安县| 永兴县| 探索| 邵阳市| 泊头市| 平凉市| 连云港市| 山丹县| 丹棱县| 织金县| 屯门区| 花垣县| 新蔡县| 平塘县| 象州县| 广饶县| 南丹县| 始兴县| 江西省| 精河县|