在TypeScript 3.8+中,使用private
关键字将成员标记为private有什么区别:
class PrivateKeywordClass {
private value = 1;
}
使用#
个私有字段proposed for JavaScript:
class PrivateFieldClass {
#value = 1;
}
我应该更喜欢其中一个吗?
在TypeScript 3.8+中,使用private
关键字将成员标记为private有什么区别:
class PrivateKeywordClass {
private value = 1;
}
使用#
个私有字段proposed for JavaScript:
class PrivateFieldClass {
#value = 1;
}
我应该更喜欢其中一个吗?
TypeScript中的private keyword是compile time注释.它告诉编译器,属性只能在该类中访问:
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
keyword也不会在运行时强制执行
将TypeScript编译为JavaScript时,只需删除private
关键字:
class PrivateKeywordClass {
private value = 1;
}
变成:
class PrivateKeywordClass {
constructor() {
this.value = 1;
}
}
由此可以看出为什么private
关键字不提供任何运行时保护:在生成的JavaScript中,它只是一个普通的JavaScript属性.
Private fields确保财产私有at runtime:
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());
如果try 在类之外使用私有字段,TypeScript还会输出编译时错误:
私有字段来自JavaScript proposal,也适用于普通JavaScript.
如果您在TypeScript中使用私有字段,并将旧版本的JavaScript作为输出目标,例如es6
或es2018
,TypeScript将try 生成模拟私有字段运行时行为的代码
class PrivateFieldClass {
constructor() {
_x.set(this, 1);
}
}
_x = new WeakMap();
如果目标是esnext
,TypeScript将发出私有字段:
class PrivateFieldClass {
constructor() {
this.#x = 1;
}
#x;
}
这取决于你想要实现什么.
private
关键字是一个很好的默认值.它完成了设计的目标,多年来一直被TypeScript开发人员成功使用.如果您有一个现有的代码库,则不需要将所有代码切换为使用私有字段.如果不是针对esnext
,这一点尤其正确,因为TS为私有字段发出的JS可能会影响性能.还要记住,私有字段与private
关键字还有其他细微但重要的区别
然而,如果您需要强制运行时私有性,或者要输出esnext
个JavaScript,那么应该使用私有字段.
还请记住,随着私有字段在JavaScript/TypeScript生态系统中变得越来越广泛,组织/社区关于使用其中一个的约定也会发生变化
私有字段不是由Object.getOwnPropertyNames
或类似的方法返回的
私有字段不按JSON.stringify
序列化
关于继承,有一些重要的边缘 case .
例如,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
}
没有初始值设定项的private
关键字私有属性不会在发出的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; }
}