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

马特·比纳

在TypeScript 3.8+中,使用private关键字将成员标记为私有之间有什么区别

class PrivateKeywordClass {
    private value = 1;
}

并使用为JavaScript建议#私有字段

class PrivateFieldClass {
    #value = 1;
}

我应该优先选择另一个吗?

马特·比纳

私人关键字

TypeScript中private关键字编译时注释。它告诉编译器,一个属性只能在该类内部访问:

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属性。

私人领域

私有字段可确保属性在运行时保持私有状态

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还将输出编译时错误:

访问私有字段时出错

专用字段来自JavaScript提案,也可以在常规JavaScript中使用。

发出的JavaScript

如果您在TypeScript中使用私有字段,并且将JavaScript的较旧版本定位为您的输出(例如es6或)es2018,则TypeScript将尝试生成模拟私有字段运行时行为的代码。

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关键字还有其他细微但重要的区别

但是,如果您需要实施运行时私有性或输出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
    }
    
  • 一个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; }
    }
    

进一步阅读:

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

运行时在private,public,package关键字之间有什么区别吗?

volatile和static关键字有什么区别?

'ref'和'out'关键字有什么区别?

'ref'和'out'关键字有什么区别?

“ type”和“ subtype”关键字有什么区别?

语句和关键字有什么区别?

“ as”和“ as!”有什么区别?迅速的关键字?

“ instanceof”和“ in”关键字之间有什么区别?

在序言中,关键字is和=有什么区别?

“数据”和“类型”关键字有什么区别?

函数和关键字/语句有什么区别?

Java中的Implements和Extended关键字有什么区别

命令行中的关键字“ python”和“ python3”有什么区别?

Dart中的“ const”和“ final”关键字有什么区别?

Java API中的“ Class”类和“ class”关键字之间有什么区别?

在Dart中,使用'new'关键字和直接调用构造函数有什么区别?

循环宏中的“ for”和“ as”关键字之间有什么区别吗?

Swift 4中private和fileprivate有什么区别

javascript 类方法 w/o 和 w function 关键字之间有什么区别?

使用和不使用`New`关键字定义数组之间有什么区别?

shell Builtin和shell关键字有什么区别?

c和c ++之间的关键字static有什么区别?

关键字“私人”和“最终”之间有什么区别?

使用box关键字和Box :: new有什么区别?

Laravel `app` 方法和 `new` 关键字有什么区别?

Webdriver.io:capabilities和desireCapabilities关键字之间有什么区别?

使用“new”关键字和不使用它有什么区别?

Java中的public,protected,package-private和private之间有什么区别?

Scala中的private和private [Class]声明有什么区别?