在 TypeScript 3.8+ 中,使用 private
有什么区别?将成员标记为私有(private)的关键字:
class PrivateKeywordClass {
private value = 1;
}
并使用
#
私有(private)领域 proposed for JavaScript :class PrivateFieldClass {
#value = 1;
}
我应该更喜欢一个吗?
最佳答案
私有(private)关键字
private keyword在 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
private
关键字也不会在运行时强制执行发出的 JavaScript
将 TypeScript 编译为 JavaScript 时,
private
关键字被简单地删除:class PrivateKeywordClass {
private value = 1;
}
变成:
class PrivateKeywordClass {
constructor() {
this.value = 1;
}
}
从这里,你可以看到为什么
private
关键字不提供任何运行时保护:在生成的 JavaScript 中,它只是一个普通的 JavaScript 属性。私有(private)字段
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());
如果您尝试在类之外使用私有(private)字段,TypeScript 也会输出编译时错误:
私有(private)字段来自 JavaScript proposal并且也可以在普通的 JavaScript 中工作。
发出的 JavaScript
如果您在 TypeScript 中使用私有(private)字段,并且输出的目标是旧版本的 JavaScript,例如
es6
或 es2018
,TypeScript 将尝试生成模拟私有(private)字段的运行时行为的代码class PrivateFieldClass {
constructor() {
_x.set(this, 1);
}
}
_x = new WeakMap();
如果您的目标是
esnext
, TypeScript 将发出私有(private)字段:class PrivateFieldClass {
constructor() {
this.#x = 1;
}
#x;
}
我应该使用哪一个?
这取决于您要达到的目标。
private
关键字是一个很好的默认值。它完成了它的设计目标,并且多年来一直被 TypeScript 开发人员成功使用。如果您有现有的代码库,则无需切换所有代码以使用私有(private)字段。如果您的目标不是 esnext
,则尤其如此。 ,因为 TS 为私有(private)字段发出的 JS 可能会对性能产生影响。还要记住,私有(private)字段与 private
有其他细微但重要的区别。关键词但是,如果您需要强制执行运行时隐私或输出
esnext
JavaScript,而不是您应该使用私有(private)字段。还要记住,随着私有(private)字段在 JavaScript/TypeScript 生态系统中变得越来越普遍,使用其中一种或另一种的组织/社区约定也会发展
其他注意事项
Object.getOwnPropertyNames
不返回私有(private)字段和类似的方法JSON.stringify
不序列化私有(private)字段例如,TypeScript 禁止在子类中声明与父类(super class)中的私有(private)属性同名的私有(private)属性。
class Base {
private value = 1;
}
class Sub extends Base {
private value = 2; // Compile error:
}
这不适用于私有(private)字段:
class Base {
#value = 1;
}
class Sub extends Base {
#value = 2; // Not an error
}
private
没有初始化器的关键字私有(private)属性将不会在发出的 JavaScript 中生成属性声明:class PrivateKeywordClass {
private value?: string;
getValue() { return this.value; }
}
编译为:
class PrivateKeywordClass {
getValue() { return this.value; }
}
而私有(private)字段总是生成一个属性声明:
class PrivateKeywordClass {
#value?: string;
getValue() { return this.#value; }
}
编译为(当目标为
esnext
时):class PrivateKeywordClass {
#value;
getValue() { return this.#value; }
}
进一步阅读:
关于typescript - TypeScript 中的 private 关键字和 private 字段有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59641564/