peScript中的private关键字和private字段有什

peScript中的private关键字和private字段有什

本文介绍了TypeScript中的private关键字和private字段有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  class PrivateKeywordClass {
私有值= 1;
}

并使用专用字段



私有字段来自,也可以在普通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 关键字



还有其他细微但重要的区别,但是如果您需要强制运行时的私有性,或者输出 esnext JavaScript,而不是使用私有字段。



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



其他音符差异




  • Object.getOwnPropertyNames 和类似方法


  • 私有字段未通过 JSON.stringify


  • 在继承方面有重要的优势案例。



    例如,TypeScript禁止声明

      class基类{
    private值= 1;
    }

    类别Sub扩展Base {
    私人价值= 2; //编译错误:
    }

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

      class Base {
    #value = 1;
    }

    class Sub扩展Base {
    #value = 2; //没有错误
    }


  • A private 没有初始化程序的关键字私有属性不会在发出的JavaScript中生成属性声明:

      class PrivateKeywordClass {
    私有值?:字符串;
    getValue(){返回this.value; }
    }

    编译为:

      class PrivateKeywordClass {
    getValue(){返回this.value; }
    }

    而私有字段始终会生成属性声明:

      class PrivateKeywordClass {
    #value ?:字符串;
    getValue(){返回this。#value; }
    }

    编译为(当定位 esnext ):

      class PrivateKeywordClass {
    #value;
    getValue(){返回this。#value; }
    }




进一步阅读:







In TypeScript 3.8+, what are the differences between using the private keyword to mark a member private:

class PrivateKeywordClass {
    private value = 1;
}

And using the # private fields proposed for JavaScript:

class PrivateFieldClass {
    #value = 1;
}

Should I prefer one over the other?

解决方案

Private keyword

The private keyword in TypeScript is a compile time annotation. It tells the compiler that a property should only be accessible inside that class:

class PrivateKeywordClass {
    private value = 1;
}

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

However compile time checking can be easily bypassed, for example by casting away the type information:

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

The privatekeyword is also not enforced at runtime

Emitted JavaScript

When compiling TypeScript to JavaScript, the private keyword is simply removed:

class PrivateKeywordClass {
    private value = 1;
}

Becomes:

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

From this, you can see why the private keyword does not offer any runtime protection: in the generated JavaScript it's just a normal JavaScript property.

Private fields

Private fields ensure that properties are kept private 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());

TypeScript will also output a compile time error if you try using a private field outside of a class:

Private fields come from a JavaScript proposal and also work in normal JavaScript.

Emitted JavaScript

If you use private fields in TypeScript and are targeting older versions of JavaScript for your output, such as es6 or es2018, TypeScript will try to generate code that emulates the runtime behavior of private fields

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

If you are targeting esnext, TypeScript will emit the private field:

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

Which one should I use?

It depends on what you are trying to achieve.

The private keyword is a fine default. It accomplishes what it was designed to accomplish and has been used successfully by TypeScript developers for years. And if you have an existing codebase, you do not need to switch all of your code to use private fields. This is especially true if you are not targeting esnext, as the JS that TS emits for private fields may have a performance impact. Also keep in mind that private fields have other subtle but important differences from the private keyword

However if you need to enforce runtime privateness or are outputting esnext JavaScript, than you should use private fields.

Also keep in mind that organization/community conventions on using one or the other will also evolve as private fields become more widespread within the JavaScript/TypeScript ecosystems

Other differences of note

  • Private fields are not returned by Object.getOwnPropertyNames and similar methods

  • Private fields are not serialized by JSON.stringify

  • There are importance edge cases around inheritance.

    TypeScript for example forbids declaring a private property in a subclass with the same name as a private property in the superclass.

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

    This is not true with private fields:

    class Base {
        #value = 1;
    }
    
    class Sub extends Base {
        #value = 2; // Not an error
    }
    

  • A private keyword private property without an initializer will not generate a property declaration in the emitted JavaScript:

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

    Compiles to:

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

    Whereas private fields always generate a property declaration:

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

    Compiles to (when targetting esnext):

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

Further reading:

这篇关于TypeScript中的private关键字和private字段有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 08:10