टाइपस्क्रिप्ट में निजी कीवर्ड और निजी फ़ील्ड के बीच अंतर क्या हैं?


27

टाइपस्क्रिप्ट 3.8+ में, का उपयोग करने के बीच क्या अंतर हैं private सदस्य को निजी चिह्नित करने के कीवर्ड :

class PrivateKeywordClass {
    private value = 1;
}

और जावास्क्रिप्ट के लिए प्रस्तावित# निजी क्षेत्रों का उपयोग करना :

class PrivateFieldClass {
    #value = 1;
}

क्या मुझे एक के बाद एक को पसंद करना चाहिए?


जवाबों:


43

निजी कीवर्ड

निजी कीवर्ड टाइपप्रति में एक है संकलन समय एनोटेशन। यह संकलक को बताता है कि एक संपत्ति केवल उस वर्ग के अंदर होनी चाहिए:

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कीवर्ड भी रनटाइम पर लागू नहीं किया जाता

जावास्क्रिप्ट का उत्सर्जन किया

टाइपस्क्रिप्ट को जावास्क्रिप्ट में संकलित करते समय, privateकीवर्ड को बस हटा दिया जाता है:

class PrivateKeywordClass {
    private value = 1;
}

हो जाता है:

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

इससे, आप देख सकते हैं कि privateकीवर्ड कोई रनटाइम सुरक्षा क्यों नहीं प्रदान करता है: उत्पन्न जावास्क्रिप्ट में यह सामान्य जावास्क्रिप्ट संपत्ति है।

निजी क्षेत्र

निजी क्षेत्रों सुनिश्चित करना है कि गुण निजी रखा जाता है कार्यावधि में :

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());

यदि आप किसी कक्षा के बाहर निजी क्षेत्र का उपयोग करने का प्रयास करते हैं, तो टाइपस्क्रिप्ट एक संकलित समय त्रुटि को भी आउटपुट करेगा:

निजी क्षेत्र तक पहुँचने में त्रुटि

निजी क्षेत्र एक जावास्क्रिप्ट प्रस्ताव से आते हैं और सामान्य जावास्क्रिप्ट में भी काम करते हैं।

जावास्क्रिप्ट का उत्सर्जन किया

यदि आप टाइपस्क्रिप्ट में निजी क्षेत्रों का उपयोग करते हैं और अपने आउटपुट के लिए जावास्क्रिप्ट के पुराने संस्करणों को लक्षित कर रहे हैं, जैसे कि es6या es2018, टाइपस्क्रिप्ट कोड उत्पन्न करने का प्रयास करेगा जो निजी क्षेत्रों के रनटाइम व्यवहार का अनुकरण करता है

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

यदि आप लक्षित कर रहे हैं esnext, तो टाइपस्क्रिप्ट निजी क्षेत्र से बाहर निकल जाएगा:

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

मुझे किसका उपयोग करना चाहिए?

यह इस बात पर निर्भर करता है कि आप क्या हासिल करने की कोशिश कर रहे हैं।

privateकीवर्ड एक ठीक डिफ़ॉल्ट है। यह पूरा करता है कि इसे क्या पूरा करने के लिए डिज़ाइन किया गया था और वर्षों से टाइपस्क्रिप्ट डेवलपर्स द्वारा सफलतापूर्वक उपयोग किया गया है। और यदि आपके पास एक मौजूदा कोडबेस है, तो आपको निजी क्षेत्रों का उपयोग करने के लिए अपने सभी कोड को स्विच करने की आवश्यकता नहीं है। यह विशेष रूप से सच है यदि आप लक्षित नहीं कर रहे हैं esnext, क्योंकि जेएस जो निजी क्षेत्रों के लिए टीएस का उत्सर्जन करता है, उसका प्रदर्शन प्रभाव हो सकता है। यह भी ध्यान रखें कि निजी क्षेत्रों में privateकीवर्ड से अन्य सूक्ष्म लेकिन महत्वपूर्ण अंतर हैं

हालाँकि, यदि आपको रनटाइम निजीकरण लागू करने की आवश्यकता है या esnextआप निजी क्षेत्रों का उपयोग करने की तुलना में जावास्क्रिप्ट का उत्पादन कर रहे हैं ।

यह भी ध्यान रखें कि एक या दूसरे का उपयोग करने पर संगठन / सामुदायिक सम्मेलन भी विकसित होंगे क्योंकि निजी क्षेत्र जावास्क्रिप्ट / टाइपस्क्रिप्ट पारिस्थितिकी प्रणालियों के भीतर अधिक व्यापक हो जाएंगे।

नोट के अन्य अंतर

  • निजी क्षेत्रों को Object.getOwnPropertyNamesऔर इसी तरह के तरीकों से वापस नहीं किया जाता है

  • निजी क्षेत्रों द्वारा क्रमबद्ध नहीं हैं JSON.stringify

  • वंशानुक्रम के चारों ओर महत्व के मामले हैं।

    उदाहरण के लिए टाइपस्क्रिप्ट सुपरक्लास में एक निजी संपत्ति के रूप में एक ही नाम के साथ एक उपवर्ग में एक निजी संपत्ति घोषित करने से मना करता है।

    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प्रारंभिक के बिना एक कीवर्ड निजी संपत्ति उत्सर्जित जावास्क्रिप्ट में एक संपत्ति घोषणा उत्पन्न नहीं करेगा:

    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; }
    }

आगे की पढाई:


4

बक्सों का इस्तेमाल करें: # -प्राकृतिक क्षेत्र

प्रस्तावना:

संकलन-समय और रन-टाइम गोपनीयता

#-प्राकृतिक क्षेत्र संकलन-समय और रन-टाइम गोपनीयता प्रदान करते हैं , जो "हैक करने योग्य" नहीं है। यह किसी भी प्रत्यक्ष तरीके से वर्ग निकाय के बाहर के सदस्य तक पहुंच को रोकने के लिए एक तंत्र है ।

class A {
    #a: number;
    constructor(a: number) {
        this.#a = a;
    }
}

let foo: A = new A(42);
foo.#a; // error, not allowed outside class bodies
(foo as any).#bar; // still nope.

सुरक्षित वर्ग विरासत

#-प्राकृतिक क्षेत्रों को एक अद्वितीय गुंजाइश मिलती है। समान गुणों वाले निजी संपत्तियों के आकस्मिक ओवरराइट के बिना वर्ग पदानुक्रम को लागू किया जा सकता है।

class A { 
    #a = "a";
    fnA() { return this.#a; }
}

class B extends A {
    #a = "b"; 
    fnB() { return this.#a; }
}

const b = new B();
b.fnA(); // returns "a" ; unique property #a in A is still retained
b.fnB(); // returns "b"

टीएस संकलक सौभाग्य से एक त्रुटि का उत्सर्जन करता है, जब privateगुण अधिलेखित होने का खतरा होता है ( इस उदाहरण को देखें )। लेकिन संकलन-समय सुविधा की प्रकृति के कारण, रन-टाइम पर सब कुछ अभी भी संभव है, दी गई संकलन त्रुटियों को अनदेखा किया जाता है और / या उत्सर्जित JS कोड का उपयोग किया जाता है।

बाहरी पुस्तकालय

लाइब्रेरी लेखक #ग्राहकों के लिए ब्रेकिंग परिवर्तन का कारण के बिना -पाइपेंट आइडेंटिफ़ायर को रिफलेक्टर कर सकते हैं। दूसरी तरफ लाइब्रेरी उपयोगकर्ता आंतरिक क्षेत्रों तक पहुँचने से सुरक्षित हैं।

जेएस एपीआई #-प्राकृतिक क्षेत्रों को छोड़ देता है

बिल्ट-इन जेएस कार्यों और तरीकों की अनदेखी-अलग-अलग #क्षेत्रों। इसके परिणामस्वरूप रन-टाइम में अधिक अनुमानित संपत्ति का चयन किया जा सकता है। उदाहरण: Object.keys, Object.entries, JSON.stringify, for..inपाश और अन्य ( कोड नमूना है, यह भी मैट Bierner देखते जवाब ):

class Foo {
    #bar = 42;
    baz = "huhu";
}

Object.keys(new Foo()); // [ "baz" ]

मामलों का उपयोग करें: privateकीवर्ड

प्रस्तावना:

आंतरिक वर्ग एपीआई और राज्य तक पहुंच (संकलन-समय केवल गोपनीयता)

privateएक वर्ग के सदस्य रन-टाइम में पारंपरिक गुण हैं। हम इस लचीलेपन का उपयोग वर्ग आंतरिक एपीआई या राज्य को बाहर से एक्सेस करने के लिए कर सकते हैं। कंपाइलर चेक को संतुष्ट करने के लिए, प्रकार के दावे, डायनेमिक प्रॉपर्टी एक्सेस जैसे तंत्र या @ts-ignoreदूसरों के बीच उपयोग किया जा सकता है।

प्रकार अभिकथन ( as/ <>) और anyटाइप किए गए चर असाइनमेंट के साथ उदाहरण :

class A { 
    constructor(private a: number) { }
}

const a = new A(10);
a.a; // TS compile error
(a as any).a; // works
const casted: any = a; casted.a // works

टीएस यहां तक ​​कि privateएक एस्केप-हैच के साथ एक सदस्य की गतिशील संपत्ति का उपयोग करने की अनुमति देता है :

class C {
  private foo = 10;
}

const res = new C()["foo"]; // 10, res has type number

निजी पहुंच कहां समझ में आ सकती है? (1) यूनिट परीक्षण, (2) डिबगिंग / लॉगिंग की स्थिति या (3) प्रोजेक्ट-इंटरनल क्लासेस (ओपन-एंडेड लिस्ट) के साथ अन्य उन्नत केस परिदृश्य।

आंतरिक चर तक पहुंच थोड़ा विरोधाभासी है - अन्यथा आपने उन्हें privateपहले स्थान पर नहीं बनाया होगा । एक उदाहरण देने के लिए, यूनिट परीक्षणों को ब्लैक / ग्रे बक्से के रूप में माना जाता है, जिसमें निजी क्षेत्र कार्यान्वयन विस्तार के रूप में छिपे होते हैं। हालांकि व्यवहार में, मामले से मान्य मान्य दृष्टिकोण हो सकते हैं।

सभी ईएस वातावरण में उपलब्ध है

टीएस privateसंशोधक का उपयोग सभी ईएस लक्ष्यों के साथ किया जा सकता है। #-प्राकृतिक क्षेत्र केवल target ES2015/ ES6या उच्चतर के लिए उपलब्ध हैं । ES6 + में, WeakMapआंतरिक रूप से डाउनलेवल कार्यान्वयन ( यहां देखें ) के रूप में उपयोग किया जाता है । #वर्तमान में मूल निवासी क्षेत्रों की आवश्यकता है target esnext

संगति और अनुकूलता

टीमें privateकेवल पहुंच संशोधक के रूप में उपयोग को लागू करने के लिए कोडिंग दिशानिर्देशों और लिंटर नियमों का उपयोग कर सकती हैं। यह प्रतिबंध #सुसंगतता के साथ मदद कर सकता है और बैकवर्ड-संगत तरीके से -पाइप फील्ड नोटेशन के साथ भ्रम से बच सकता है।

यदि आवश्यक हो, पैरामीटर गुण (कंस्ट्रक्टर असाइनमेंट आशुलिपि) एक शो स्टॉपर हैं। उन्हें केवल privateकीवर्ड के साथ उपयोग किया जा सकता है और -प्राकृतिक क्षेत्रों को लागू करने के लिए अभी तक कोई योजना नहीं है #

अन्य कारण

  • privateकुछ डाउन-लेवलिंग मामलों में बेहतर रन-टाइम प्रदर्शन प्रदान करें ( यहां देखें )।
  • टीएस में अब तक कोई कठिन निजी कक्षा विधियाँ उपलब्ध नहीं हैं।
  • कुछ लोगों को privateकीवर्ड नोटेशन बेहतर not पसंद है।

दोनों पर ध्यान दें

दोनों दृष्टिकोण संकलन-समय पर कुछ प्रकार के नाममात्र या ब्रांडेड प्रकार बनाते हैं।

class A1 { private a = 0; }
class A2 { private a = 42; }

const a: A1 = new A2(); 
// error: "separate declarations of a private property 'a'"
// same with hard private fields

इसके अलावा, दोनों क्रॉस-इंस्टेंस एक्सेस की अनुमति देते हैं: क्लास का एक उदाहरण Aअन्य Aउदाहरणों के निजी सदस्यों तक पहुंच सकता है :

class A {
    private a = 0;
    method(arg: A) {
        console.log(arg.a); // works
    }
}

सूत्रों का कहना है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.