TypeScript 中的 private 关键字和私有字段有什么区别?

2023-12-30

在 TypeScript 3.8+ 中,使用private将成员标记为私有的关键字:

class PrivateKeywordClass {
    private value = 1;
}

并使用#私人领域建议用于 JavaScript https://github.com/tc39/proposal-class-fields#private-fields:

class PrivateFieldClass {
    #value = 1;
}

我应该选择其中之一而不是另一种吗?


私人关键字

The 私有关键字 https://www.typescriptlang.org/docs/handbook/classes.html#understanding-private在 TypeScript 中是编译时间注解。它告诉编译器属性只能在该类内部访问:

class PrivateKeywordClass {
    private value = 1;
}

const obj = new PrivateKeywordClass();
obj.value // compiler error: Property 'value' is private and only accessible within class 'PrivateKeywordClass'.

然而,编译时检查很容易被绕过,例如通过丢弃类型信息:

const obj = new PrivateKeywordClass();
(obj as any).value // no compile error

The private 关键字在运行时也不会强制执行

发出的 JavaScript

将 TypeScript 编译为 JavaScript 时,private关键字被简单地删除:

class PrivateKeywordClass {
    private value = 1;
}

Becomes:

class PrivateKeywordClass {
    constructor() {
        this.value = 1;
    }
}

从这里你可以看出为什么private关键字不提供任何运行时保护:在生成的 JavaScript 中,它只是一个普通的 JavaScript 属性。

私人领域

私人领域 https://github.com/tc39/proposal-class-fields#private-fields确保财产保密在运行时:

class PrivateFieldClass {
    #value = 1;

    getValue() { return this.#value; }
}

const obj = new PrivateFieldClass();

// You can't access '#value' outside of class like this
obj.value === undefined // This is not the field you are looking for.
obj.getValue() === 1 // But the class itself can access the private field!

// Meanwhile, using a private field outside a class is a runtime syntax error:
obj.#value

// While trying to access the private fields of another class is 
// a runtime type error:
class Other {
    #value;

    getValue(obj) {
        return obj.#value // TypeError: Read of private field #value from an object which did not contain the field
    }
}

new Other().getValue(new PrivateKeywordClass());

如果您尝试在类之外使用私有字段,TypeScript 也会输出编译时错误:

私有字段源自TC-39 ECMAScript 提案 https://github.com/tc39/proposal-class-fields#private-fields并且是 2021 ECMAScript 规范的一部分,这意味着它们可以在普通 JavaScript 和 TypeScript 中使用。

发出的 JavaScript

如果您在 TypeScript 中使用私有字段,并且目标是 ES2021 或更早版本的 JavaScript 进行输出,TypeScript 将生成模拟私有字段运行时行为的代码,使用WeakMap https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap (source https://www.typescriptlang.org/docs/handbook/2/classes.html#caveats)

class PrivateFieldClass {
    constructor() {
        _x.set(this, 1);
    }
}
_x = new WeakMap();

如果您的目标是 ES2021 之后的任何内容,TypeScript 将发出私有字段:

class PrivateFieldClass {
    constructor() {
        this.#x = 1;
    }
    #x;
}

我应该使用哪一个?

这取决于您想要实现的目标。

The private关键字是一个很好的默认值。它实现了它的设计目标,并且已被 TypeScript 开发人员成功使用多年。如果您有现有的代码库,则无需将所有代码切换为使用私有字段。如果您没有瞄准目标,则尤其如此esnext,因为 TS 为私有字段发出的 JS 可能会对性能产生影响。另请记住,私有字段与私有字段还有其他微妙但重要的区别private keyword

但是,如果您需要强制运行时隐私或正在输出esnextJavaScript,而不是你应该使用私有字段。

另请记住,随着私有字段在 JavaScript/TypeScript 生态系统中变得更加普遍,组织/社区关于使用其中一种或另一种的约定也将不断发展

其他值得注意的差异

  • 私有字段不会被返回Object.getOwnPropertyNames和类似的方法

  • 私有字段不被序列化JSON.stringify

  • 继承有一些重要的边缘情况。

    例如,TypeScript 禁止在子类中声明与超类中的私有属性同名的私有属性。

    class Base {
        private value = 1;
    }
    
    class Sub extends Base {
        private value = 2; // Compile error:
    }
    

    对于私有字段来说,情况并非如此:

    class Base {
        #value = 1;
    }
    
    class Sub extends Base {
        #value = 2; // Not an error
    }
    
  • A private没有初始化器的关键字 private property 将不会在发出的 JavaScript 中生成属性声明:

    class PrivateKeywordClass {
        private value?: string;
        getValue() { return this.value; }
    }
    

    编译为:

    class PrivateKeywordClass {
        getValue() { return this.value; }
    }
    

    而私有字段总是生成属性声明:

    class PrivateKeywordClass {
        #value?: string;
        getValue() { return this.#value; }
    }
    

    编译为(当目标为esnext):

    class PrivateKeywordClass {
        #value;
        getValue() { return this.#value; }
    }
    

进一步阅读:

  • “private”关键字的未来 https://github.com/microsoft/TypeScript/issues/31670
  • 添加私有字段的 TypeScript PR https://github.com/microsoft/TypeScript/pull/30829
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TypeScript 中的 private 关键字和私有字段有什么区别? 的相关文章

随机推荐

  • AD用户认证

    我正在尝试创建一个 ASP NET NET 3 5 网站以通过 Exchange Web 服务连接到我们的 Exchange 2010 服务器 当我定义要进行身份验证的用户名 密码和域时 我能够连接到 EWS 但我想 如果可能的话 不要在我
  • Google 电子表格中单元格文本的 sha3-256

    我知道你可以在谷歌表格上做 sha1 和其他 但是有没有办法做 sha3 256 secret test123 hash 3054762b0a8b31adfe79efb3bc7718624627cc99c7c8f39bfa591ce6854
  • 访问 iCloud 通知中已删除的对象

    我有一个应用程序设置非常类似于 iCloudCoreDataRecipes 示例 即 将 Core Data 与 iCloud 结合使用 在应用程序委托中 我观察到 NSPersistentStoreDidImportUbiquitousC
  • 图像配准(非刚性\非线性)

    我正在寻找一些算法 最好是如果源代码可用 用于图像配准 图像变形不能用单应矩阵来描述 因为我认为变形不是对称的 不是 均匀 更具体地说 变形就像桶形 扭曲和梯形扭曲 可能是图像的一些旋转 我想获得两个图像的像素对 这样我就可以获得 变形场
  • 在 C 编程中避免为串联分配大量内存

    提供的代码从文本文件中读取行并将它们存储在称为lines的动态分配的二维数组中 该模式始终在第32767行之后重复 然后它连接特定的行 lines j lines k lines m 并将结果打印在输出文件中 问题是我的 input txt
  • Backbone.js 和 PushState

    如果我在主干路由器中启用pushState 我是否需要在所有链路上使用return false 或者主干路由器是否会自动处理此问题 是否有任何示例 包括 html 部分和脚本部分 这是蒂姆 布兰延 Tim Branyen 在他的作品中使用的
  • 下划线的 PyCharm 代码完成设置 - 受保护和损坏的名称优先级较低?

    我正在使用 PyCharm 但我不喜欢显示的默认代码完成 protected and mangled名字高于public 我怎样才能强制显示以下划线在代码完成列表的底部 在顶部公开 像 PyDev 这样的一些编辑器在没有配置的情况下做得更好
  • Django 模板中的动态块

    这是一个关于 django 的问题 我完全找不到答案 假设我有一个网站 在侧边栏中显示两个块 最后登录的用户的列表 最近发表的博客文章的列表 假设这些块将显示在 80 的网站 URL 上并使用模板文件呈现 这些块的数据是由代码生成的 显然
  • jQuery $(窗口).resize();等效的事件侦听器,仅在指定的轴更改时触发?

    我正在寻找一个事件监听器 它的工作原理类似于 jQuery resize 但仅当调整大小的对象 谈论窗口 在 x 轴或两者上调整大小时触发 但不仅仅在 y 轴上调整大小 所以基本上它只会监听宽度的调整大小事件 您可以将窗口加载时浏览器的宽度
  • JqueryUI Autocomplete: autoFocus = true 不会做任何事情

    我有这个带有自动完成功能的输入 autocomplete source jsonR php minLength 2 select function event ui this val ui item value llamar include
  • 嵌入式系统的 Google 测试

    我想使用 Google Tests 为我的嵌入式应用程序软件编写单元测试 这些测试将在用 C 编写的应用软件上执行 应用程序软件使用的驱动程序 例如I2C SPI 故障断言是用 C 编写的 我的问题是 什么是一个好的起点 我的意思是我可以阅
  • linux 传递 gcc mcrypt.h 位置的正确标志

    我已经编译了libmcrypt从源头到 home mybin 确认以下内容为所需文件的位置 home mybin include mcrypt h home mybin include mutils mcrypt h home mybin
  • 如何创建 /etc/subuid 和 /etc/subgid

    我的 Manjaro 安装没有配置 etc subuid and etc subgidDocker 等无根容器工作所需的文件 例如cat etc subuid返回文件未找到错误 我一安装 Docker Desktop 就发现了这个问题 并且
  • 如何识别矩阵中每行哪些列不是“NA”?

    我有一个 12 行 77 列的矩阵 但为了简单地让我们使用 p lt matrix NA 5 7 p 1 2 lt 0 3 p 1 3 lt 0 5 p 2 4 lt 0 9 p 2 7 lt 0 4 p 4 5 lt 0 6 我想知道哪些
  • 在 Rstudio 中使用 keras 时,如何使绘图显示在 Rmarkdown 文件中而不是查看器窗格中?

    我是新来的R并尝试keras in Rstudio 一切accuracy loss通过运行 fit 的交互式图出现在Viewer窗格而不是Rmarkdown file 所有其他图通常都绘制在内部Rmarkdown文件 但不适用于 keras
  • Android Studio 构建正常,Gradle 命令行失败

    我已将一个应用程序从 Eclipse 移植到 Android Studio 实现了我需要的风格并允许它在 Android Studio 中工作 由于风格的数量 我更喜欢使用命令行 Gradle 来构建它 但是 当我运行以下命令来构建我的发布
  • IN 与具有大型行集的 JOIN

    我想选择一个表中的行 其中主键位于另一个表中 我不确定是否应该在 SQL Server 2005 中使用 JOIN 或 IN 运算符 对于大型数据集 即数百万行 这两个 SQL 查询之间是否存在显着的性能差异 SELECT FROM a W
  • Java:纪元日期为 MM/DD/YYYY

    我的时间 1386696238 我的代码 Date date new Date Long parseLong currentNotification getDate created SimpleDateFormat formatter ne
  • 为什么 Java 将方法的大小限制为 65535 字节?

    我刚刚编译了以下代码 public class A public static void main String args int i 3 i i i i i i i i repeat writing the expression i fo
  • TypeScript 中的 private 关键字和私有字段有什么区别?

    在 TypeScript 3 8 中 使用private将成员标记为私有的关键字 class PrivateKeywordClass private value 1 并使用 私人领域建议用于 JavaScript https github