जब मैं सक्षम नहीं होना चाहिए तो मैं टाइपस्क्रिप्ट निजी सदस्यों तक क्यों पहुंच सकता हूं?


108

मैं टाइपस्क्रिप्ट में निजी सदस्यों के कार्यान्वयन को देख रहा हूं, और मुझे यह थोड़ा भ्रमित लगता है। Intellisense निजी सदस्य का उपयोग करने की अनुमति नहीं देता है, लेकिन शुद्ध जावास्क्रिप्ट में, यह सब वहाँ है। इससे मुझे लगता है कि टीएस निजी सदस्यों को सही तरीके से लागू नहीं करता है। कोई विचार?

class Test{
  private member: any = "private member";
}
alert(new Test().member);

आप सोच रहे हैं कि IntelliSense आपको अलर्ट () के साथ पंक्ति में निजी सदस्य क्यों नहीं देता है?
व्यवस्थित करें

7
नहीं। मैं सोच रहा हूं कि टीएस के पास एक निजी क्यों है जब वह केवल इंटेलीजेंस के लिए चीनी है, और वास्तव में जावास्क्रिप्ट के लिए नहीं जो इसके लिए संकलित है। इस कोड को execcriptlang.org/Playground अलर्ट निजी सदस्य मान में निष्पादित करता है ।
सीन फेल्डमैन

जैसा कि उल्लेख किया गया है, आपको एक निजी संदर्भ में उन्हें निजी होने के लिए एक चर के रूप में आइटम घोषित करना होगा। मैं अनुमान लगा रहा हूं कि टाइपस्क्रिप्ट ऐसा नहीं करता है क्योंकि यह अयोग्य बनाम प्रोटोटाइप में जोड़ सकता है। यह प्रकार की परिभाषा के साथ भी गड़बड़ करता है (निजी सदस्य वास्तव में कक्षा का हिस्सा नहीं हैं)
शेन

यदि आप वास्तविक निजी चर चाहते हैं जो प्रोटोटाइप पर मौजूद हैं, तो यह कुछ ओवरहेड ले जाता है, लेकिन मैंने ClassJS नामक एक लाइब्रेरी लिखी है जो GitHub: github.com/KthProg/ClassJS पर ऐसा करता है ।
KthProg

जवाबों:


97

जिस प्रकार जाँच के साथ, सदस्यों की गोपनीयता केवल संकलक के भीतर लागू होती है।

एक निजी संपत्ति को एक नियमित संपत्ति के रूप में लागू किया जाता है, और कक्षा के बाहर कोड को इसे एक्सेस करने की अनुमति नहीं है।

कक्षा के अंदर कुछ वास्तव में निजी बनाने के लिए, यह कक्षा का सदस्य नहीं हो सकता है, यह कोड के अंदर एक फ़ंक्शन स्कोप के अंदर बनाया गया एक स्थानीय चर होगा जो ऑब्जेक्ट बनाता है। इसका मतलब यह होगा कि आप इसे thisकीवर्ड का उपयोग करके कक्षा के सदस्य की तरह एक्सेस नहीं कर सकते ।


25
यह एक जावास्क्रिप्ट प्रोग्रामर के लिए असामान्य नहीं है कि वह किसी ऑब्जेक्ट कंस्ट्रक्टर में एक स्थानीय वैरिएबल डाले और निजी क्षेत्र के रूप में उपयोग करे। मुझे आश्चर्य है कि उन्होंने ऐसा कुछ समर्थन नहीं किया।
एरिक

2
@ एरिक: जैसा कि टाइपस्क्रिप्ट निर्माणकर्ता के अंदर प्रोटोटाइप के रूप में तरीकों को जोड़ने के बजाय तरीकों के लिए प्रोटोटाइप का उपयोग करता है, कंस्ट्रक्टर में एक स्थानीय चर विधियों से उपलब्ध नहीं है। क्लास के लिए फंक्शन रैपर के अंदर एक स्थानीय वैरिएबल बनाना संभव हो सकता है, लेकिन मुझे अभी तक ऐसा करने का कोई तरीका नहीं मिला है। हालाँकि, यह अभी भी एक स्थानीय चर होगा, और एक निजी सदस्य नहीं होगा।
गुफ्फा

40
यह कुछ ऐसा है जिस पर मैं प्रतिक्रिया दे रहा हूं। मेरा मानना ​​है कि इसे एक खुलासा मॉड्यूल पैटर्न बनाने का विकल्प पेश करना चाहिए, ताकि निजी सदस्य निजी रह सकें और सार्वजनिक रूप से जावास्क्रिप्ट में पहुंच सकें। यह एक सामान्य पैटर्न है और TS और JS में समान पहुँच प्रदान करेगा।
जॉन पापा

एक समाधान है जिसे आप निजी स्थैतिक सदस्यों के लिए उपयोग कर सकते हैं: basarat.com/2013/03/real-private-static-class-members-in.html
basarat

1
@ बसरतअली: यह एक स्थिर चर है जो कक्षा के तरीकों के अंदर उपलब्ध है, लेकिन यह कक्षा का सदस्य नहीं है, अर्थात आप इसे thisकीवर्ड का उपयोग करके एक्सेस नहीं करते हैं ।
गुफा

37

जावास्क्रिप्ट निजी चर का समर्थन करता है।

function MyClass() {
    var myPrivateVar = 3;

    this.doSomething = function() {
        return myPrivateVar++;        
    }
}

टाइपस्क्रिप्ट में यह इस तरह व्यक्त किया जाएगा:

class MyClass {

    doSomething: () => number;

    constructor() {
        var myPrivateVar = 3;

        this.doSomething = function () {
            return myPrivateVar++;
        }
    }
}

संपादित करें

इस दृष्टिकोण का उपयोग केवल स्‍पार्किंगली ही किया जाना चाहिए जहां इसकी नितांत आवश्‍यकता हो। उदाहरण के लिए यदि आपको अस्थायी रूप से पासवर्ड कैश करने की आवश्यकता है।

इस पैटर्न (जावास्क्रिप्ट या टाइपस्क्रिप्ट के अप्रासंगिक) का उपयोग करने के लिए प्रदर्शन लागतें हैं और केवल जहां आवश्यक हो, वहां उपयोग किया जाना चाहिए।


टाइप किए गए var _thisकार्यों में उपयोग के लिए सेटिंग करके यह हर समय टाइपस्क्रिप्ट नहीं करता है ? आप इसे क्लास के दायरे में क्यों कर रहे हैं?
DrSammyD

नहीं। var _this यह केवल एक संदर्भ है।
मार्टिन

2
अधिक सटीक रूप से उन्हें कंस्ट्रक्टर चर कहा जाता है, निजी नहीं। वे प्रोटोटाइप तरीकों में दिखाई नहीं दे रहे हैं।
रोमन एम। कोस

1
ओह, हाँ, क्षमा करें समस्या एक थी इसके बजाय, यह तथ्य कि आपके द्वारा बनाए गए प्रत्येक उदाहरण के लिए, doSomething को फिर से बनाया जाएगा, क्योंकि यह प्रोटोटाइप श्रृंखला का हिस्सा नहीं है।
बारू बारबु

1
@BarbuBarbu हां मैं सहमत हूं। यह इस दृष्टिकोण के साथ एक बड़ा मुद्दा है, और इसके कारणों में से एक को टाला जाना चाहिए।
मार्टिन

11

एक बार WeakMap के लिए समर्थन अधिक व्यापक रूप से उपलब्ध है एक दिलचस्प तकनीक उदाहरण # 3 में यहां विस्तृत है

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

लिंक किए गए MDN WeakMap पेज क्रोम 36, फ़ायरफ़ॉक्स 6.0, IE 11, ओपेरा 23 और सफारी 7.1 पर ब्राउज़र समर्थन को सूचीबद्ध करता है।

let _counter = new WeakMap();
let _action = new WeakMap();
class Countdown {
  constructor(counter, action) {
    _counter.set(this, counter);
    _action.set(this, action);
  }
  decrement() {
    let counter = _counter.get(this);
    if (counter < 1) return;
    counter--;
    _counter.set(this, counter);
    if (counter === 0) {
      _action.get(this)();
    }
  }
}

मुझे अच्छा लगा! मूल रूप से इसका मतलब है निजी संपत्तियों को एकत्रित वर्ग में छिपाना। सबसे मजेदार होगा ... protectedमापदंडों के समर्थन को कैसे जोड़ा जाए ? : D
रोमन एम। कोस

2
@RamtinSoltani लिंक किए गए लेख आँकड़े हैं कि कैसे कमजोर काम करने के कारण, यह कचरा संग्रहण को नहीं रोक पाएगा। यदि कोई इस तकनीक का उपयोग करते समय अतिरिक्त सुरक्षित होना चाहता था, तो वे अपने स्वयं के निपटान कोड को लागू कर सकते थे जो प्रत्येक कमजोर वर्ग से वर्ग उदाहरण कुंजी को हटा देता है।
रयान थॉमस

1
MDN पृष्ठ से: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… । इसके विपरीत, मूल WeakMaps प्रमुख वस्तुओं के लिए "कमजोर" संदर्भ रखता है, जिसका अर्थ है कि वे कचरा संग्रह को नहीं रोकते हैं यदि कुंजी वस्तु का कोई अन्य संदर्भ नहीं होगा। यह मानचित्र में मूल्यों के कचरा संग्रह को रोकने से भी बचता है।
रयान थॉमस

@RyanThomas सच, यह एक पुरानी टिप्पणी थी जिसे मैंने कुछ समय पहले छोड़ा था। मैप्स के विपरीत, WeakMaps, मेमोरी लीक का कारण नहीं होगा। इसलिए इस तकनीक का उपयोग करना सुरक्षित है।
रामतिन सोल्टानी

@RamtinSoltani तो अपने पुराने टिप्पणी को हटाना>?
ErikE

10

चूंकि टाइपस्क्रिप्ट 3.8 जारी किया जाएगा, आप निजी क्षेत्र की घोषणा करने में सक्षम होंगे, जिसे एक्सेस नहीं किया जा सकता है या यहां तक ​​कि युक्त वर्ग के बाहर भी पता लगाया जा सकता है

class Person {
    #name: string

    constructor(name: string) {
        this.#name = name;
    }

    greet() {
        console.log(`Hello, my name is ${this.#name}!`);
    }
}

let jeremy = new Person("Jeremy Bearimy");

jeremy.#name
//     ~~~~~
// Property '#name' is not accessible outside class 'Person'
// because it has a private identifier.

निजी क्षेत्र #चरित्र से शुरू होते हैं

कृपया ध्यान दें कि ये निजी फ़ील्ड privateकीवर्ड से चिह्नित फ़ील्ड से कुछ अलग होंगे

संदर्भ। https://devblogs.microsoft.com/typescript/announcing-typescript-3-8-beta/


4

इस मुद्दे पर आधिकारिक चर्चा के लिंक के लिए सीन फेल्डमैन का धन्यवाद - लिंक के लिए उनका जवाब देखें ।

मैंने उनसे जुड़ी चर्चा को पढ़ा और यहाँ प्रमुख बिंदुओं का सारांश दिया गया है:

  • सुझाव: निर्माता में निजी गुण
    • समस्याओं: प्रोटोटाइप कार्यों से पहुँच नहीं कर सकते
  • सुझाव: निर्माता में निजी तरीके
    • समस्याएं: गुणों के साथ ही, साथ ही आप प्रोटोटाइप में कक्षा में एक बार एक फ़ंक्शन बनाने का प्रदर्शन लाभ खो देते हैं; इसके बजाय आप प्रत्येक उदाहरण के लिए फ़ंक्शन की एक प्रति बनाते हैं
  • सुझाव: अमूर्त संपत्ति का उपयोग करने के लिए बॉयलरप्लेट जोड़ें और दृश्यता को लागू करें
    • समस्याओं: प्रमुख प्रदर्शन ओवरहेड; टाइपस्क्रिप्ट को बड़े अनुप्रयोगों के लिए डिज़ाइन किया गया है
  • सुझाव: टाइपस्क्रिप्ट पहले से ही एक बंद में निर्माता और प्रोटोटाइप विधि परिभाषा को लपेटता है; वहां निजी तरीके और गुण लगाएं
    • निजी संपत्तियों को उस बंद करने में समस्याएँ: वे स्थिर चर बन जाते हैं; प्रति उदाहरण एक नहीं है
    • निजी तरीकों को उस बंद करने में समस्याएँ: वे thisकिसी प्रकार के समाधान के बिना उपयोग नहीं करते हैं
  • सुझाव: स्वचालित रूप से निजी चर नामों को नियंत्रित करें
    • काउंटर तर्क: यह एक नामकरण सम्मेलन है, न कि एक भाषा निर्माण। इसे अपने आप में ढालो
  • सुझाव:@private निजीकृत तरीकों को ऐसे मिनीफायर्स से पहचानें कि एनोटेशन प्रभावी रूप से विधि के नामों का उल्लेख कर सकता है
    • इसके लिए कोई महत्वपूर्ण काउंटर तर्क नहीं

उत्सर्जित कोड में दृश्यता समर्थन जोड़ने के लिए कुल मिलाकर तर्क:

  • समस्या यह है कि जावास्क्रिप्ट स्वयं दृश्यता संशोधक नहीं है - यह टाइपस्क्रिप्ट की समस्या नहीं है
  • जावास्क्रिप्ट समुदाय में पहले से ही एक स्थापित पैटर्न है: एक अंडरस्कोर के साथ निजी गुणों और विधियों का उपसर्ग, जो कहता है "अपने स्वयं के धन पर आगे बढ़ें"
  • जब टाइपस्क्रिप्ट डिजाइनरों ने कहा कि वास्तव में निजी गुण और विधियां "संभव" नहीं हैं, तो उनका मतलब था "विशेष रूप से हमारे डिजाइन बाधाओं के तहत संभव नहीं":
    • उत्सर्जित JS मुहावरेदार है
    • बॉयलरप्लेट न्यूनतम है
    • सामान्य जेएस ओओपी की तुलना में कोई अतिरिक्त ओवरहेड नहीं

यदि यह उत्तर इस वार्तालाप से था: टाइपस्क्रिप्ट.कोडप्लेक्स.com / discussions / 397651 -, कृपया एक लिंक प्रदान करें: D
रोमन एम। कोस

1
हां, यह बातचीत है - लेकिन मैंने सीन फेल्डमैन के इस सवाल के जवाब से जोड़ा , जहां वह लिंक प्रदान करता है। चूंकि उन्होंने लिंक खोजने का काम किया था, इसलिए मैं उन्हें इसका श्रेय देना चाहता था।
अलेक्जेंडरबर्ड

2

टाइपस्क्रिप्ट में निजी कार्य केवल कक्षा के अंदर ही सुलभ हैं। पसंद

यहां छवि विवरण दर्ज करें

और जब आप किसी निजी सदस्य तक पहुँचने का प्रयास करेंगे तो यह एक त्रुटि दिखाएगा। यहाँ उदाहरण है:

यहां छवि विवरण दर्ज करें

नोट: यह जावास्क्रिप्ट के साथ ठीक होगा और दोनों फ़ंक्शन बाहर सुलभ हैं।


4
ओपी: "लेकिन शुद्ध जावास्क्रिप्ट में, यह सब वहां है" - मुझे नहीं लगता कि आप इस मुद्दे को संबोधित करते हैं कि उत्पन्न जावास्क्रिप्ट "निजी" कार्यों को सार्वजनिक रूप से उजागर करता है
एलेक्सेंडरबर्ड

1
@alexanderbird मुझे लगता है कि वह कहना चाहता था कि टाइपस्क्रिप्ट आमतौर पर पर्याप्त है। जब हम टाइपस्क्रिप्ट में विकसित कर रहे हैं, तो हम परियोजना के दायरे में इसके साथ रहते हैं, इसलिए जावास्क्रिप्ट से गोपनीयता कोई बड़ी बात नहीं है। क्योंकि सबसे पहले, डेवलपर के लिए मूल कोड मायने रखता है, ट्रांसपेल्ड (जावास्क्रिप्ट) वाले नहीं।
रोमन एम। कोस

1
आप जब तक कर रहे हैं लेखन और एक JavaScript लाइब्रेरी का प्रकाशन, तो transpiled कोड फर्क पड़ता है
alexanderbird

आपका उत्तर ऑफ टॉपिक है।
कैनबक्स

1

मुझे लगता है कि यह एक पुरानी चर्चा है, लेकिन यह अभी भी संकलित जावास्क्रिप्ट वर्ग के सार्वजनिक इंटरफेस में "लीक" में कथित निजी चर और तरीकों की समस्या के लिए मेरे समाधान को साझा करने के लिए उपयोगी हो सकता है।

मेरे लिए यह मुद्दा विशुद्ध रूप से कॉस्मेटिक है, अर्थात यह दृश्य अव्यवस्था के बारे में है जब एक उदाहरण चर DevTools में देखा जाता है। मेरा फिक्स एक और वर्ग के अंदर एक साथ निजी घोषणाओं को समूहित करना है जो कि मुख्य कक्षा में तुरंत तैयार किया गया है और एक private(लेकिन अभी भी सार्वजनिक रूप से जेएस में दिखाई दे रहा है) जैसे नाम __(डबल अंडरस्कोर) के साथ असाइन किया गया है ।

उदाहरण:

class Privates {
    readonly DEFAULT_MULTIPLIER = 2;
    foo: number;
    bar: number;

    someMethod = (multiplier: number = this.DEFAULT_MULTIPLIER) => {
        return multiplier * (this.foo + this.bar);
    }

    private _class: MyClass;

    constructor(_class: MyClass) {
        this._class = _class;
    }
}

export class MyClass {
    private __: Privates = new Privates(this);

    constructor(foo: number, bar: number, baz: number) {
        // assign private property values...
        this.__.foo = foo;
        this.__.bar = bar;

        // assign public property values...
        this.baz = baz;
    }

    baz: number;

    print = () => {
        console.log(`foo=${this.__.foo}, bar=${this.__.bar}`);
        console.log(`someMethod returns ${this.__.someMethod()}`);
    }
}

let myClass = new MyClass(1, 2, 3);

जब myClassउदाहरण DevTools में देखा जाता है, तो इसके सभी "निजी" सदस्यों को वास्तव में सार्वजनिक लोगों के साथ दखल देने के बजाय (जो ठीक से वास्तविक जीवन के कोड में बहुत नेत्रहीन गड़बड़ मिल सकता है) आप उन्हें बड़े करीने से मिली __संपत्ति के अंदर बड़े करीने से देखते हैं:

यहां छवि विवरण दर्ज करें


1
मुझें यह पसंद है। साफ दिखता है।

0

यहां उचित निजी संपत्तियों को जोड़ने के लिए पुन: प्रयोज्य दृष्टिकोण दिया गया है:

/**
 * Implements proper private properties.
 */
export class Private<K extends object, V> {

    private propMap = new WeakMap<K, V>();

    get(obj: K): V {
        return this.propMap.get(obj)!;
    }

    set(obj: K, val: V) {
        this.propMap.set(obj, val);
    }
}

मान लीजिए कि आपके पास Clientकहीं ऐसी कक्षा है जिसमें दो निजी संपत्तियों की आवश्यकता है:

  • prop1: string
  • prop2: number

नीचे आप इसे कैसे लागू करते हैं:

// our private properties:
interface ClientPrivate {
    prop1: string;
    prop2: number;
}

// private properties for all Client instances:
const pp = new Private<Client, ClientPrivate>();

class Client {
    constructor() {
        pp.set(this, {
            prop1: 'hello',
            prop2: 123
        });
    }

    someMethod() {
        const privateProps = pp.get(this);

        const prop1 = privateProps.prop1;
        const prop2 = privateProps.prop2;
    }
}

और अगर आप सभी की जरूरत है एक निजी संपत्ति है, तो यह और भी सरल हो जाता है, क्योंकि आपको ClientPrivateउस मामले में किसी भी परिभाषित करने की आवश्यकता नहीं होगी ।

वर्थ नोटिंग, कि अधिकांश भाग के लिए, क्लास Privateसिर्फ एक अच्छी तरह से पठनीय हस्ताक्षर प्रदान करता है, जबकि प्रत्यक्ष उपयोग WeakMapनहीं करता है।

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