जावास्क्रिप्ट ईएस 6 कक्षाओं में निजी गुण


444

क्या ES6 कक्षाओं में निजी संपत्तियां बनाना संभव है?

यहाँ एक उदाहरण है। मैं कैसे तक पहुँच को रोक सकता हूँ instance.property?

class Something {
  constructor(){
    this.property = "test";
  }
}

var instance = new Something();
console.log(instance.property); //=> "test"

5
इस फीचर के लिए वास्तव में स्टेज 3 प्रस्ताव है - tc39.github.io/proposal-class-fields github.com/tc39/proposal-class-fields
arty

@arty मैंने इसके उदाहरण के साथ एक उत्तर दिया है: stackoverflow.com/a/52237988/1432509
एलिस्टर

जवाबों:


165

ईसीएमए मानक में निजी क्षेत्रों (और विधियों) को लागू किया जा रहा है । आप उन्हें आज बबल 7 और स्टेज 3 प्रीसेट के साथ उपयोग करना शुरू कर सकते हैं ।

class Something {
  #property;

  constructor(){
    this.#property = "test";
  }

  #privateMethod() {
    return 'hello world';
  }

  getPrivateMessage() {
      return this.#privateMethod();
  }
}

const instance = new Something();
console.log(instance.property); //=> undefined
console.log(instance.privateMethod); //=> undefined
console.log(instance.getPrivateMessage()); //=> hello world

मैं सोच रहा हूं कि वो क्लास फील्ड कैसे काम कर सकते हैं। thisकॉल करने से पहले आप वर्तमान में कंस्ट्रक्टर में उपयोग नहीं कर सकते super()। फिर भी बेबल ने उन्हें सुपर से पहले रखा।
साधक_ऑफ_बाकॉन

#privateCrapसिंटैक्स की अनुमति देने के लिए ESLint को कैसे कॉन्फ़िगर करें ?
मारेकी

6
और पलायन के बारे में क्या? मुझे बराबर चिह्न पर पार्सर त्रुटि मिली। बैबेल काम कर रहा है, बस इस नए js वाक्यविन्यास को पार्सल नहीं कर सकता।
21

6
वाह यह बहुत बदसूरत है। हैशटैग एक मान्य चरित्र है। संपत्ति वास्तव में निजी नहीं है, या? .. मैंने इसे टाइपस्क्रिप्ट में जांचा। निजी सदस्यों को निजी या केवल-पठन (बाहर से) में संकलित नहीं किया जाता है। बस एक और (सार्वजनिक) संपत्ति की तरह घोषित किया। (ES5)।
डोमिनिक

2
आप इसके साथ निजी तरीके कैसे लिखते हैं ? क्या मैं ऐसा कर सकता हूं #beep() {}:; और इस: async #bzzzt() {}?
Константин Ван

277

संक्षिप्त उत्तर, नहीं, ES6 कक्षाओं के साथ निजी संपत्तियों के लिए कोई मूल समर्थन नहीं है।

लेकिन आप नए गुणों को ऑब्जेक्ट में संलग्न न करके उस व्यवहार की नकल कर सकते हैं, लेकिन उन्हें एक क्लास कंस्ट्रक्टर के अंदर रख सकते हैं, और छिपे हुए गुणों तक पहुंचने के लिए गेटर्स और सेटर का उपयोग कर सकते हैं। ध्यान दें कि कक्षा के प्रत्येक नए उदाहरण पर गेटर्स और सेटर्स को फिर से परिभाषित किया जाता है।

ES6

class Person {
    constructor(name) {
        var _name = name
        this.setName = function(name) { _name = name; }
        this.getName = function() { return _name; }
    }
}

ES5

function Person(name) {
    var _name = name
    this.setName = function(name) { _name = name; }
    this.getName = function() { return _name; }
}

1
मुझे यह घोल सबसे अच्छा लगता है। मैं मानता हूं कि इसे स्केलिंग के लिए इस्तेमाल नहीं किया जाना चाहिए, लेकिन यह उन वर्गों के लिए एकदम सही है जो आमतौर पर केवल एक बार शामिल किए जाने के बाद तुरंत हो जाएंगे।
ब्लेक रेगलिया

2
साथ ही आप इस वर्ग के हर एक घटक को नए सिरे से बनाए जाने पर हर बार पुनर्परिभाषित कर रहे हैं।
क्वेंटिन रॉय

10
यह बहुत अजीब है! ES6 में आप ES6 से पहले अधिक "क्लोजर पिरामिड" बना रहे हैं! ऊपर दिए गए ES5 उदाहरण में एक निर्माता के साथ फ़ंक्शंस को परिभाषित करना बदसूरत लगता है।
कोकोडको

1
चूंकि ओपी विशेष रूप से ईएस 6 वर्गों के बारे में पूछता है, मुझे व्यक्तिगत रूप से लगता है कि यह एक खराब समाधान है, भले ही यह तकनीकी रूप से काम करता हो। प्रमुख सीमा यह है कि अब निजी चर का उपयोग करने वाली प्रत्येक कक्षा पद्धति को कंस्ट्रक्टर के अंदर घोषित किया जाना चाहिए, classपहले स्थान पर सिंटैक्स होने के फायदे को गंभीर रूप से कम करके ।
नैनोवेयर

10
यह सब करता है अप्रत्यक्ष परिचय। अब आप कैसे getNameऔर setNameगुणों को निजी बनाते हैं ?
ऐज

195

@ Loganfsmyth के उत्तर पर विस्तार करने के लिए:

जावास्क्रिप्ट में केवल सही मायने में निजी डेटा अभी भी scoped चर है। आपके पास निजी संपत्तियां नहीं हो सकती हैं जो कि सार्वजनिक संपत्तियों की तरह ही आंतरिक रूप से एक्सेस की गई हैं, लेकिन आप निजी डेटा को स्टोर करने के लिए स्कोप किए गए चर का उपयोग कर सकते हैं।

बंद चर

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

उदाहरण:

function Person(name) {
  let age = 20; // this is private
  this.name = name; // this is public

  this.greet = function () {
    // here we can access both name and age
    console.log(`name: ${this.name}, age: ${age}`);
  };
}

let joe = new Person('Joe');
joe.greet();

// here we can access name but not age

स्कोप कमजोर

पिछले दृष्टिकोण के प्रदर्शन और मेमोरी पेनल्टी से बचने के लिए WeakMap का उपयोग किया जा सकता है। WeakMaps वस्तुओं (यहां, उदाहरणों) के साथ डेटा को इस तरह से जोड़ता है कि इसे केवल उस WeakMap का उपयोग करके एक्सेस किया जा सकता है। इसलिए, हम निजी WeakMap बनाने के लिए scoped चर विधि का उपयोग करते हैं, फिर उस WeakMap का उपयोग निजी डेटा से संबंधित करने के लिए करते हैंthis । यह स्कोप्ड वैरिएबल विधि से अधिक तेज़ है क्योंकि आपके सभी इंस्टेंसेस एक सिंगल वेकपेज़ को साझा कर सकते हैं, इसलिए आपको केवल अपने खुद के WeakMaps का उपयोग करने के लिए तरीकों को फिर से बनाने की आवश्यकता नहीं है।

उदाहरण:

let Person = (function () {
  let privateProps = new WeakMap();

  class Person {
    constructor(name) {
      this.name = name; // this is public
      privateProps.set(this, {age: 20}); // this is private
    }

    greet() {
      // Here we can access both name and age
      console.log(`name: ${this.name}, age: ${privateProps.get(this).age}`);
    }
  }

  return Person;
})();

let joe = new Person('Joe');
joe.greet();

// here we can access joe's name but not age

यह उदाहरण कई निजी संपत्तियों के लिए एक WeakMap का उपयोग करने के लिए ऑब्जेक्ट का उपयोग करता है; आप कई WeakMaps का उपयोग कर सकते हैं और उनका उपयोग कर सकते हैं age.set(this, 20), या एक छोटा आवरण लिख सकते हैं और इसे किसी अन्य तरीके से उपयोग कर सकते हैं, जैसेprivateProps.set(this, 'age', 0)

इस दृष्टिकोण की गोपनीयता सैद्धांतिक रूप से वैश्विक के साथ छेड़छाड़ करके भंग हो सकती है WeakMap वस्तु के । उस ने कहा, सभी जावास्क्रिप्ट को मैंगल्ड ग्लोबल्स द्वारा तोड़ा जा सकता है। हमारा कोड पहले से ही इस धारणा पर बना है कि ऐसा नहीं हो रहा है।

(इस विधि के साथ भी किया जा सकता है Map, लेकिन WeakMapबेहतर है क्योंकि Mapमेमोरी लीक तब तक बनेगी जब तक आप बहुत सावधान न हों, और इस उद्देश्य के लिए दोनों अलग-अलग नहीं हैं।)

आधा-उत्तर: प्रतीकात्मक चिह्न

एक प्रतीक एक आदिम मूल्य है जो एक संपत्ति के नाम के रूप में काम कर सकता है। आप निजी चिह्न बनाने के लिए स्कोप की गई परिवर्तनशील पद्धति का उपयोग कर सकते हैं, फिर निजी डेटा को यहां संग्रहीत कर सकते हैंthis[mySymbol]

इस पद्धति की गोपनीयता का उपयोग करके उल्लंघन किया जा सकता है Object.getOwnPropertySymbols , लेकिन ऐसा करने के लिए कुछ अजीब है।

उदाहरण:

let Person = (function () {
  let ageKey = Symbol();

  class Person {
    constructor(name) {
      this.name = name; // this is public
      this[ageKey] = 20; // this is intended to be private
    }

    greet() {
      // Here we can access both name and age
      console.log(`name: ${this.name}, age: ${this[ageKey]}`);
    }
  }

  return Person;
})();

let joe = new Person('Joe');
joe.greet();

// Here we can access joe's name and, with a little effort, age. ageKey is
// not in scope, but we can obtain it by listing all Symbol properties on
// joe with `Object.getOwnPropertySymbols(joe)`.

अर्ध-उत्तर: अंडरस्कोर

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

उदाहरण:

class Person {
  constructor(name) {
    this.name = name; // this is public
    this._age = 20; // this is intended to be private
  }

  greet() {
    // Here we can access both name and age
    console.log(`name: ${this.name}, age: ${this._age}`);
  }
}

let joe = new Person('Joe');
joe.greet();

// Here we can access both joe's name and age. But we know we aren't
// supposed to access his age, which just might stop us.

निष्कर्ष

ES2017 के अनुसार, निजी संपत्तियों को करने का कोई सही तरीका नहीं है। विभिन्न दृष्टिकोणों के पक्ष और विपक्ष हैं। स्कोप किए गए चर वास्तव में निजी हैं; स्कोप्ड WeakMaps स्कूप्ड वैरिएबल्स की तुलना में बहुत निजी और अधिक व्यावहारिक हैं; स्कोप किए गए प्रतीक यथोचित निजी और यथोचित व्यावहारिक हैं; अंडरस्कोर अक्सर पर्याप्त निजी और बहुत व्यावहारिक होते हैं।


7
पहला उदाहरण स्निपेट ("स्कोप्ड वैरिएबल") कुल एंटीपैटर्न है - प्रत्येक लौटी हुई वस्तु का एक अलग वर्ग होगा। ऐसा मत करो। यदि आप विशेषाधिकार प्राप्त तरीके चाहते हैं, तो उन्हें निर्माता में बनाएँ।
बरगी

1
एक फ़ंक्शन के अंदर एक वर्ग लपेटकर पहली जगह में कक्षाओं का उपयोग करने के पूरे उद्देश्य को हराने के लिए लगता है। यदि आप पहले से ही एक उदाहरण बनाने के लिए फ़ंक्शन का उपयोग करते हैं, तो आप अपने सभी निजी / सार्वजनिक सदस्यों को उस फ़ंक्शन के अंदर भी रख सकते हैं, और पूरे क्लास कीवर्ड के बारे में भूल सकते हैं।
कोकोडको 13

2
@Bergi @ Kokodoko मैंने स्कॉप्ड वैरिएबल एप्रोच को थोड़ा तेज किया और ब्रेक नहीं किया instanceof। मैं मानता हूं कि मैं उस दृष्टिकोण के बारे में सोच रहा था जिसमें केवल पूर्णता की खातिर शामिल किया गया था और अधिक विचार करना चाहिए था कि यह वास्तव में कितना सक्षम है।
ट्रिस्टन डेस

1
बहुत बढ़िया स्पष्टीकरण! मुझे अभी भी आश्चर्य है कि वास्तव में ES6 ने एक निजी चर का अनुकरण करना कठिन बना दिया है, जहां ES5 में आप बस निजी और सार्वजनिक अनुकरण करने के लिए एक फ़ंक्शन के अंदर var और इसका उपयोग कर सकते हैं।
कोकोडको

2
@ कोकोडको यदि आप वर्ग के साथ विचरण करते हैं और फ़ंक्शन में सब कुछ डालते हैं, तो आपको प्रोटोटाइप पद्धति का उपयोग करके विरासत को लागू करने के लिए भी वापस करना होगा। कक्षाओं पर विस्तार का उपयोग करना अब तक एक क्लीनर दृष्टिकोण है, इसलिए किसी फ़ंक्शन के अंदर कक्षा का उपयोग करना पूरी तरह से स्वीकार्य है।
AndroidDev

117

अपडेट: अच्छे सिंटैक्स के साथ एक प्रस्ताव चल रहा है। योगदान का स्वागत है।


हाँ, वहाँ है - वस्तुओं में पहुँच के लिए - ES6 परिचय Symbolएस

प्रतीक अद्वितीय हैं, आप प्रतिबिंब के अलावा बाहर से एक तक पहुंच प्राप्त नहीं कर सकते हैं (जैसे जावा / सी # में निजीकरण), लेकिन कोई भी जिसके पास प्रतीक पर एक्सेस है, वह इसे कुंजी एक्सेस के लिए उपयोग कर सकता है:

var property = Symbol();
class Something {
    constructor(){
        this[property] = "test";
    }
}

var instance = new Something();

console.log(instance.property); //=> undefined, can only access with access to the Symbol

6
क्या आप उपयोग नहीं कर सकते Object.getOwnPropertySymbols? ;)
कांटा 94 हेवी

41
@BenjaminGruenbaum: स्पष्ट रूप से प्रतीक अब सही गोपनीयता सुनिश्चित नहीं करते हैं: stackoverflow.com/a/22280202/1282216
d13

28
@ तत्र कुंजी के माध्यम से? प्रतीकों के माध्यम से नहीं? हाँ। बहुत पसंद है कि आप निजी क्षेत्रों तक पहुंचने के लिए C # और जावा जैसी भाषाओं में प्रतिबिंब का उपयोग कैसे कर सकते हैं। एक्सेस संशोधक सुरक्षा के बारे में नहीं हैं - वे इरादे की स्पष्टता के बारे में हैं।
बेंजामिन ग्रुएनबाम

9
ऐसा लगता है कि प्रतीक का उपयोग करना करने के समान है const myPrivateMethod = Math.random(); Something.prototype[''+myPrivateMethod] = function () { ... } new Something()[''+myPrivateMethod]();। यह वास्तव में गोपनीयता नहीं है, यह पारंपरिक जावास्क्रिप्ट के अर्थ में अस्पष्टता है। मैं "निजी" जावास्क्रिप्ट पर विचार करूंगा जिसका अर्थ है कि वैरिएबल को बंद करने के लिए क्लोजर का उपयोग करना। इसलिए वे चर प्रतिबिंब के माध्यम से सुलभ नहीं हैं।
trusktr

13
इसके अलावा, मुझे लगता है कि कीवर्ड्स privateऔर protectedकीवर्ड्स का उपयोग करना Symbolया की तुलना में बहुत अधिक क्लीनर होगा Name। मैं ब्रैकेट नोटेशन के बजाय डॉट नोटेशन पसंद करता हूं। मैं निजी चीजों के लिए डॉट का उपयोग करना चाहता हूं। this.privateVar
trusktr

33

जवाब न है"। लेकिन आप इस तरह की संपत्तियों की निजी पहुंच बना सकते हैं:

  • मॉड्यूल का उपयोग करें। एक मॉड्यूल में सब कुछ निजी है जब तक कि यह exportकीवर्ड का उपयोग करके सार्वजनिक नहीं किया जाता है ।
  • मॉड्यूल के अंदर, फंक्शन क्लोजर का उपयोग करें: http://www.kirupa.com/html5/closures_in_javascript.htm

(यह सुझाव कि गोपनीयता सुनिश्चित करने के लिए प्रतीकों का इस्तेमाल किया जा सकता है ES6 युक्ति के पुराने संस्करण में सत्य था, लेकिन अब ऐसा नहीं है: https://mail.mozilla.org/pipermail/es-discuss/2014-Januge/035604। html और https://stackoverflow.com/a/22280202/1282216 । प्रतीकों और गोपनीयता के बारे में एक लंबी चर्चा के लिए देखें: https://curiosity-driven.org/pStreet-properties-in-javascript )


6
-1, यह आपके प्रश्न का वास्तव में उत्तर नहीं देता है। (आप ES5 में IIFE के साथ क्लोजर का भी उपयोग कर सकते हैं)। अधिकांश भाषाओं (जावा, C #, आदि) में प्रतिबिंब के माध्यम से निजी गुण उल्लेखनीय हैं। निजी संपत्तियों की बात अन्य प्रोगामर्स के इरादे को व्यक्त करना है और सुरक्षा को लागू नहीं करना है।
बेंजामिन ग्रुएनबाम

1
@BenjaminGruenbaum, मुझे पता है, काश मेरे पास एक बेहतर जवाब होता, मैं इससे खुश नहीं होता।
d13

मुझे लगता है कि प्रतीकों को अभी भी प्रोग्रामिंग वातावरण में दुर्गम सदस्यों को प्राप्त करने का एक वैध तरीका है। हां, वे तब भी मिल सकते हैं यदि आप वास्तविक रूप से चाहते हैं, लेकिन यह बात नहीं है? आपको इसमें संवेदनशील जानकारी संग्रहीत नहीं करनी चाहिए, लेकिन आपको क्लाइंट साइड कोड में वैसे भी ऐसा नहीं करना चाहिए। लेकिन यह किसी बाहरी वर्ग से संपत्ति या विधि को छिपाने के उद्देश्य से काम करता है।
कोकोडको

एक मॉड्यूल के स्तर पर स्कूप किए गए चर का उपयोग करके एक वर्ग में निजी गुणों के विकल्प के रूप में एक सिंगलटन के लिए नेतृत्व किया जाएगा।
एड्रियन मोइसा

30

जेएस में सच्ची गोपनीयता प्राप्त करने का एकमात्र तरीका स्कूपिंग के माध्यम से है, इसलिए संपत्ति रखने का कोई तरीका नहीं है जो इसका एक सदस्य है thisजो केवल घटक के अंदर ही सुलभ होगा। ES6 में सही मायने में निजी डेटा स्टोर करने का सबसे अच्छा तरीका एक WeakMap के साथ है।

const privateProp1 = new WeakMap();
const privateProp2 = new WeakMap();

class SomeClass {
  constructor() {
    privateProp1.set(this, "I am Private1");
    privateProp2.set(this, "I am Private2");

    this.publicVar = "I am public";
    this.publicMethod = () => {
      console.log(privateProp1.get(this), privateProp2.get(this))
    };        
  }

  printPrivate() {
    console.log(privateProp1.get(this));
  }
}

जाहिर है कि यह शायद धीमा है, और निश्चित रूप से बदसूरत है, लेकिन यह गोपनीयता प्रदान करता है।

ध्यान रखें कि EVEN THIS सही नहीं है, क्योंकि जावास्क्रिप्ट इतना गतिशील है। अभी भी कोई कर सकता था

var oldSet = WeakMap.prototype.set;
WeakMap.prototype.set = function(key, value){
    // Store 'this', 'key', and 'value'
    return oldSet.call(this, key, value);
};

मूल्यों को पकड़ने के लिए, क्योंकि वे संग्रहीत हैं, इसलिए यदि आप अतिरिक्त सावधानी बरतना चाहते हैं, तो आपको स्थानीय प्रोटोटाइप पर भरोसा करने के बजाय एक स्थानीय संदर्भ को कैप्चर करना होगा .setऔर .getस्पष्ट रूप से उपयोग करना होगा।

const {set: WMSet, get: WMGet} = WeakMap.prototype;

const privateProp1 = new WeakMap();
const privateProp2 = new WeakMap();

class SomeClass {
  constructor() {
    WMSet.call(privateProp1, this, "I am Private1");
    WMSet.call(privateProp2, this, "I am Private2");

    this.publicVar = "I am public";
    this.publicMethod = () => {
      console.log(WMGet.call(privateProp1, this), WMGet.call(privateProp2, this))
    };        
  }

  printPrivate() {
    console.log(WMGet.call(privateProp1, this));
  }
}

3
सुझाव के रूप में, आप मूल्य के रूप में एक वस्तु का उपयोग करके प्रति संपत्ति एक कमजोर मानचित्र का उपयोग करने से बच सकते हैं। इस तरह आप नक्शे की संख्या को getप्रति विधि (जैसे const _ = privates.get(this); console.log(_.privateProp1);) घटा सकते हैं ।
क्वेंटिन रॉय

हाँ, यह पूरी तरह से एक विकल्प भी है। मैं ज्यादातर इस के साथ चला गया क्योंकि यह वास्तविक गुणों का उपयोग करते समय एक उपयोगकर्ता द्वारा लिखे गए नक्शे से अधिक सीधे होता है।
loganfsmyth

@loganfsmyth const myObj = new SomeClass(); console.log(privateProp1.get(myObj)) // "I am Private1"का मतलब है कि आपकी संपत्ति निजी है या नहीं?
बारबू बारू

2
उस काम के लिए, संपत्ति तक पहुंचने वाले कोड को वीकपॉइंट ऑब्जेक्ट तक पहुंच की आवश्यकता होगी, जो आमतौर पर एक मॉड्यूल और दुर्गम के अंदर बंद हो जाएगा
loganfsmyth

22

दर्शकों पर अन्य के भविष्य के संदर्भ के लिए, मैं अब सुन रहा हूँ कि सिफारिश WeakMaps का उपयोग करने के लिए है निजी डेटा रखने के का ।

यहाँ एक और अधिक स्पष्ट, काम करने वाला उदाहरण है:

function storePrivateProperties(a, b, c, d) {
  let privateData = new WeakMap;
  // unique object as key, weak map can only accept object as key, when key is no longer referened, garbage collector claims the key-value 
  let keyA = {}, keyB = {}, keyC = {}, keyD = {};

  privateData.set(keyA, a);
  privateData.set(keyB, b);
  privateData.set(keyC, c);
  privateData.set(keyD, d);

  return {
    logPrivateKey(key) {
      switch(key) {
      case "a":
        console.log(privateData.get(keyA));
        break;
      case "b":
        console.log(privateData.get(keyB));
        break;
      case "c":
        console.log(privateData.get(keyC));
        break;
      case "d":
        console.log(privateData.set(keyD));
        break;
      default:
        console.log(`There is no value for ${key}`)
      }
    }
  }
}

20
ध्यान रखें कि ये गुण स्थिर हैं।
माइकल थेरॉट

8
मैंने आपको निराश नहीं किया, लेकिन आपका कमजोर उदाहरण पूरी तरह से गलत है।
बेंजामिन ग्रुएनबाम

4
अर्थात् - आप सभी वर्ग उदाहरणों के बीच डेटा साझा कर रहे हैं और प्रति उदाहरण नहीं - क्या मैं कम से कम इसे ठीक कर सकता हूं?
बेंजामिन ग्रुएनबाम

1
दरअसल, कमज़ोर को किसी दिए गए उदाहरण से जुड़ा होना चाहिए। उदाहरण के लिए fitzgeraldnick.com/weblog/53 देखें ।
चौड़ा किया

2
एमडीएन के अनुसार, प्रतीक के रूप में आदिम डेटा प्रकारों को एक WeakMap कुंजी के रूप में अनुमति नहीं है। एमडीएन वीकएप डॉक्यूमेंटेशन
लेपॉवेल

12

निर्भर करता है कि आप किससे पूछते हैं :-)

कोई भी privateसंपत्ति संशोधक मैक्सिमली न्यूनतम वर्गों के प्रस्ताव में शामिल नहीं है जो लगता है कि इसे वर्तमान मसौदे में शामिल किया गया है

हालांकि, निजी नामों के लिए समर्थन हो सकता है , जो निजी संपत्तियों की अनुमति देता है - और संभवतः उन्हें कक्षा की परिभाषाओं में भी इस्तेमाल किया जा सकता है।


3
यह अत्यधिक संभावना नहीं है कि निजी नाम ईएस 6 में बना देंगे, हालांकि वे ईएस 7 के लिए निजी चीज़ के कुछ रूप के बारे में सोच रहे हैं।
कांटास 94 हेवी

@ Qantas94Heavy दोनों निजी नामों और अद्वितीय स्ट्रिंग मानों को मैं जो समझता हूं, उससे प्रतीक द्वारा अलग कर दिया गया है।
बेंजामिन ग्रुएनबाम

हाँ, यह शायद प्रतीक बन जाएगा। हालाँकि, वर्तमान में युक्ति में निहित "प्रतीकों" का उपयोग केवल [[प्रोटोटाइप]] जैसे आंतरिक गुणों का वर्णन करने के लिए किया जाता है, और उपयोगकर्ता कोड में उन्हें बनाने और उपयोग करने का कोई तरीका नहीं है। क्या आप कुछ डॉक्स जानते हैं?
बर्गी

मुझे बस एहसास हुआ कि गोपनीयता को सेट करने के लिए मॉड्यूल का उपयोग किया जा सकता है। प्रतीकों के साथ संयुक्त है कि आप कभी भी आवश्यकता हो सकती है ...?
d13

1
@ कोडी : आपके पूरे मॉड्यूल कोड का ES6 में वैसे भी अपना दायरा है, IEFE की कोई आवश्यकता नहीं है। और हाँ, प्रतीकों को विशिष्टता (टकराव-परिहार) के लिए रखा गया है, गोपनीयता नहीं।
बरगी

10

ES6 मॉड्यूल का उपयोग करना (शुरू में @ d13 द्वारा प्रस्तावित) मेरे लिए अच्छा काम करता है। यह पूरी तरह से निजी संपत्तियों की नकल नहीं करता है, लेकिन कम से कम आप आश्वस्त हो सकते हैं कि जो गुण निजी होने चाहिए वह आपकी कक्षा के बाहर लीक नहीं होंगे। यहाँ एक उदाहरण है:

something.js

let _message = null;
const _greet = name => {
  console.log('Hello ' + name);
};

export default class Something {
  constructor(message) {
    _message = message;
  }

  say() {
    console.log(_message);
    _greet('Bob');
  }
};

तब खपत कोड इस तरह दिख सकता है:

import Something from './something.js';

const something = new Something('Sunny day!');
something.say();
something._message; // undefined
something._greet(); // exception

अद्यतन (महत्वपूर्ण):

जैसा कि @DanyalAytekin टिप्पणियों में उल्लिखित है, ये निजी गुण स्थिर हैं, इसलिए गुंजाइश में वैश्विक हैं। सिंग्लेटन्स के साथ काम करते समय वे अच्छी तरह से काम करेंगे, लेकिन क्षणिक वस्तुओं के लिए देखभाल की जानी चाहिए। उपरोक्त उदाहरण का विस्तार:

import Something from './something.js';
import Something2 from './something.js';

const a = new Something('a');
a.say(); // a

const b = new Something('b');
b.say(); // b

const c = new Something2('c');
c.say(); // c

a.say(); // c
b.say(); // c
c.say(); // c

4
के लिए अच्छा है private static
डेनियल आयटेकिन

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

जितना अधिक मैं कार्यात्मक प्रोग्रामिंग (विशेष रूप से एल्म और हास्केल) के बारे में सीखता हूं, उतना ही मुझे विश्वास है कि जेएस प्रोग्रामर एक ओओपी वर्ग-आधारित के बजाय एक मॉड्यूल-आधारित दृष्टिकोण से "न्यूनाधिकता" तक लाभान्वित होंगे। यदि हम ईएस 6 मॉड्यूल को अनुप्रयोगों के निर्माण की नींव के रूप में सोचते हैं, और पूरी तरह से कक्षाओं के बारे में भूल जाते हैं, तो मेरा मानना ​​है कि हम समग्र रूप से बेहतर अनुप्रयोगों के साथ समाप्त हो सकते हैं। क्या कोई अनुभवी एल्म या हास्केल उपयोगकर्ता इस दृष्टिकोण पर टिप्पणी कर सकता है?
d13

1
अपडेट में, दूसरा a.say(); // aहोना चाहिएb.say(); // b
grokky

let _message = nullजिस तरह से कोशिश की है, इतना अच्छा नहीं है, जब कई बार निर्माता को बुलाओ, यह गड़बड़ है।
लिटिल

9

@ J13ny-oshika और @DanyalAytekin द्वारा @ d13 और टिप्पणियों को पूरा करना:

मुझे लगता है कि @ जॉनी-ओशिका द्वारा उपलब्ध कराए गए उदाहरण में हम तीर के कार्यों के बजाय सामान्य कार्यों का उपयोग कर सकते हैं और फिर .bindउन्हें वर्तमान वस्तु के साथ एक _privatesवस्तु के रूप में एक क्यूरेटेड पैरामीटर:

something.js

function _greet(_privates) {
  return 'Hello ' + _privates.message;
}

function _updateMessage(_privates, newMessage) {
  _privates.message = newMessage;
}

export default class Something {
  constructor(message) {
    const _privates = {
      message
    };

    this.say = _greet.bind(this, _privates);
    this.updateMessage = _updateMessage.bind(this, _privates);
  }
}

main.js

import Something from './something.js';

const something = new Something('Sunny day!');

const message1 = something.say();
something.updateMessage('Cloudy day!');
const message2 = something.say();

console.log(message1 === 'Hello Sunny day!');  // true
console.log(message2 === 'Hello Cloudy day!');  // true

// the followings are not public
console.log(something._greet === undefined);  // true
console.log(something._privates === undefined);  // true
console.log(something._updateMessage === undefined);  // true

// another instance which doesn't share the _privates
const something2 = new Something('another Sunny day!');

const message3 = something2.say();

console.log(message3 === 'Hello another Sunny day!'); // true

वे लाभ जो मैं सोच सकता हूँ:

  • हमारे पास निजी विधियाँ हो सकती हैं ( _greetऔर _updateMessageजब तक हम exportसंदर्भ नहीं देते हैं, निजी विधियों की तरह कार्य करते हैं )
  • हालाँकि वे प्रोटोटाइप पर नहीं हैं, उपर्युक्त तरीके मेमोरी को बचाएंगे क्योंकि इंस्टेंसेस एक बार, क्लास के बाहर बनाए जाते हैं (जैसा कि कंस्ट्रक्टर में उन्हें परिभाषित करने का विरोध किया गया है)
  • हम किसी भी ग्लोबल्स को लीक नहीं करते हैं क्योंकि हम एक मॉड्यूल के अंदर हैं
  • हमारे पास बाइंड की गई _privatesवस्तु का उपयोग करके निजी गुण भी हो सकते हैं

कुछ कमियां जो मैं सोच सकता हूं:

एक चल स्निपेट यहां पाया जा सकता है: http://www.webpackbin.com/NJgI5JSTZ


8

हां - आप इनकैप्सुलेटेड प्रॉपर्टी बना सकते हैं , लेकिन यह एक्सेस मॉडिफायर्स (पब्लिक | प्राइवेट) के साथ नहीं किया गया है, कम से कम ES6 के साथ नहीं।

यहाँ एक सरल उदाहरण है कि यह ES6 के साथ कैसे किया जा सकता है:

1 कक्षा का उपयोग करके कक्षा बनाएं शब्द

2 अंदर यह कंस्ट्रक्टर let या const का उपयोग करके ब्लॉक-स्कोपेड वैरिएबल घोषित करता है आरक्षित शब्दों -> चूंकि वे ब्लॉक-स्कोप हैं, उन्हें बाहर से एक्सेस नहीं किया जा सकता है (इनकैप्सुलेटेड)

3 उन चर के लिए कुछ अभिगम नियंत्रण (जमाकर्ता | गेटर्स) की अनुमति देने के लिए आप इसका उपयोग कर निर्माणकर्ता के अंदर उदाहरण विधि की घोषणा कर सकते हैं: this.methodName=function(){}वाक्यविन्यास

"use strict";
    class Something{
        constructor(){
            //private property
            let property="test";
            //private final (immutable) property
            const property2="test2";
            //public getter
            this.getProperty2=function(){
                return property2;
            }
            //public getter
            this.getProperty=function(){
                return property;
            }
            //public setter
            this.setProperty=function(prop){
                property=prop;
            }
        }
    }

अब इसे जाँचते हैं:

var s=new Something();
    console.log(typeof s.property);//undefined 
    s.setProperty("another");//set to encapsulated `property`
    console.log(s.getProperty());//get encapsulated `property` value
    console.log(s.getProperty2());//get encapsulated immutable `property2` value

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

@ फ्रीज़िस्टम फर्स्ट: पहले वे इंस्टेंस मेथड हैं (क्लास के तरीके नहीं)। दूसरा ओपी प्रश्न था: _ मैं उदाहरण के लिए एक्सेस कैसे रोक सकता हूं।
प्रोपेर्ट्टी__

1
मैं यह नहीं कह रहा था कि आप गलत थे, मैंने कहा कि आपका समाधान इस तथ्य के बावजूद निजी चर प्राप्त करने के लिए सबसे अच्छा समझौता था कि हर बार आपके द्वारा कॉल किए जाने पर प्रत्येक इंस्टेंस विधियों की एक प्रति बनाई जाती है new Something();क्योंकि आपके तरीकों को इन तक पहुंचने के लिए कंस्ट्रक्टर में घोषित किया जाता है निजी चर। यदि आप अपनी कक्षा का बहुत अधिक उदाहरण बनाते हैं, तो बहुत अधिक मेमोरी खपत हो सकती है, इसलिए प्रदर्शन समस्याएँ। विधायक दायरे के बाहर तरीके घोषित किए जाने चाहिए थे। मेरी टिप्पणी एक आलोचना की तुलना में आपके समाधान की कमियों की अधिक व्याख्या थी।
फ्रीजिस्टिक्स

1
लेकिन क्या यह बुरा अभ्यास आपके पूरे वर्ग को कंस्ट्रक्टर के अंदर परिभाषित नहीं करता है? क्या हम अब सिर्फ "हैकिंग" जावास्क्रिप्ट नहीं कर रहे हैं? बस किसी भी अन्य ओओपी प्रोग्रामिंग भाषा को देखें, और आप देखेंगे कि निर्माणकर्ता एक वर्ग को परिभाषित करने के लिए नहीं है।
कोकोडको

1
हाँ, यही मेरा मतलब है, और आपका समाधान काम करता है! मैं सिर्फ इतना कह रहा हूं कि सामान्य तौर पर मुझे आश्चर्य है कि ES6 ने एक 'क्लास' कीवर्ड जोड़ा है, लेकिन एनकैप्सुलेशन को प्राप्त करने के लिए var और इस के साथ काम करने के सुरुचिपूर्ण समाधान को हटा दिया है।
कोकोडोको

8

"निजी" के लिए एक अलग दृष्टिकोण

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

ऑटो-पब्लिक सिर्फ सार्वजनिक सामान दिखा रहा है


1
समस्या यह है, कि हम संपादक के ऊपर निजी चर का उपयोग नहीं करना चाहते हैं, हम बाहर से निजी चर की रक्षा नहीं करेंगे - और वह यह है कि सार्वजनिक / निजी क्या करता है। यदि आपका कोड समाप्त हो गया है, तो आप कक्षा के बाहर से इन चरों को एक्सेस कर सकते हैं (और महत्वपूर्ण विचार: ओवरराइड )। आपकी @privateटिप्पणी इन पर रोक नहीं लगा सकती है, यह केवल प्रलेखन-पीढ़ी के लिए एक विशेषता है और आईडीआर आईडीई है।
एड्रियन प्रेयस

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

6

WeakMap

  • IE11 में समर्थित (प्रतीक नहीं हैं)
  • हार्ड-प्राइवेट (प्रतीक का उपयोग करने वाले प्रॉपर सॉफ्ट-प्राइवेट हैं Object.getOwnPropertySymbols)
  • वास्तव में साफ दिख सकते हैं (क्लोजर के विपरीत, जिसे कंस्ट्रक्टर में सभी सहारा और तरीकों की आवश्यकता होती है)

सबसे पहले, WeakMap को लपेटने के लिए एक फ़ंक्शन को परिभाषित करें:

function Private() {
  const map = new WeakMap();
  return obj => {
    let props = map.get(obj);
    if (!props) {
      props = {};
      map.set(obj, props);
    }
    return props;
  };
}

फिर, अपनी कक्षा के बाहर एक संदर्भ बनाएँ:

const p = new Private();

class Person {
  constructor(name, age) {
    this.name = name;
    p(this).age = age; // it's easy to set a private variable
  }

  getAge() {
    return p(this).age; // and get a private variable
  }
}

नोट: वर्ग IE11 द्वारा समर्थित नहीं है, लेकिन यह उदाहरण में क्लीनर दिखता है।


6

ओह, इतने सारे विदेशी समाधान! मैं आमतौर पर गोपनीयता के बारे में परवाह नहीं करता हूं इसलिए मैं "छद्म गोपनीयता" का उपयोग करता हूं क्योंकि यह यहां कहा गया है । लेकिन अगर परवाह है (अगर उसके लिए कुछ विशेष आवश्यकताएं हैं) तो मैं इस उदाहरण में कुछ का उपयोग करता हूं:

class jobImpl{
  // public
  constructor(name){
    this.name = name;
  }
  // public
  do(time){
    console.log(`${this.name} started at ${time}`);
    this.prepare();
    this.execute();
  }
  //public
  stop(time){
    this.finish();
    console.log(`${this.name} finished at ${time}`);
  }
  // private
  prepare(){ console.log('prepare..'); }
  // private
  execute(){ console.log('execute..'); }
  // private
  finish(){ console.log('finish..'); }
}

function Job(name){
  var impl = new jobImpl(name);
  return {
    do: time => impl.do(time),
    stop: time => impl.stop(time)
  };
}

// Test:
// create class "Job"
var j = new Job("Digging a ditch");
// call public members..
j.do("08:00am");
j.stop("06:00pm");

// try to call private members or fields..
console.log(j.name); // undefined
j.execute(); // error

फ़ंक्शन का दूसरा संभावित कार्यान्वयन (निर्माता) Job:

function Job(name){
  var impl = new jobImpl(name);
  this.do = time => impl.do(time),
  this.stop = time => impl.stop(time)
}

5

व्यक्तिगत रूप से मुझे बाइंड ऑपरेटर का प्रस्ताव पसंद है ::और फिर इसे @ d13 उल्लिखित समाधान के साथ जोड़ देगा, लेकिन अब @ d13 के उत्तर के साथ चिपकाएं जहां आप exportअपनी कक्षा के लिए कीवर्ड का उपयोग करते हैं और मॉड्यूल में निजी फ़ंक्शन डालते हैं।

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

Private.js

export const get = state => key => state[key];
export const set = state => (key,value) => { state[key] = value; }

Test.js

import { get, set } from './utils/Private'
export default class Test {
  constructor(initialState = {}) {
    const _set = this.set = set(initialState);
    const _get = this.get = get(initialState);

    this.set('privateMethod', () => _get('propValue'));
  }

  showProp() {
    return this.get('privateMethod')();
  }
}

let one = new Test({ propValue: 5});
let two = new Test({ propValue: 8});
two.showProp(); // 8
one.showProp(); // 5

इस पर टिप्पणी की सराहना की जाएगी।


आम तौर पर मुझे दृष्टिकोण पसंद है। प्रतिक्रिया: 1. क्लैशिंग को रोकने के लिए आपको प्रत्येक वर्ग के लिए एक अलग प्राइवेट.जेएस मॉड्यूल की आवश्यकता होगी। 2. मैं आपके प्रत्येक निजी तरीकों को इनलाइन-परिभाषित करके कंस्ट्रक्टर को वास्तव में लंबा बनाने की क्षमता को नापसंद करता हूं। 3. यह अच्छा होगा यदि क्लास के सभी तरीके एक फाइल में हों।
डग कोबर्न

5

मैं इस पोस्ट के दौरान आया जब "कक्षाओं के लिए निजी डेटा" के लिए सर्वोत्तम अभ्यास की तलाश कर रहा था। यह उल्लेख किया गया था कि कुछ पैटर्न में प्रदर्शन के मुद्दे होंगे।

मैंने ऑनलाइन पुस्तक "एक्स्प्लोरिंग ईएस 6" से 4 मुख्य पैटर्न के आधार पर कुछ जेस्पर्फ़ परीक्षण किए।

http://exploringjs.com/es6/ch_classes.html#sec_private-data-for-classes

परीक्षण यहाँ पाए जा सकते हैं:

https://jsperf.com/private-data-for-classes

क्रोम 63.0.3239 / मैक ओएस एक्स 10.11.6 में, सबसे अच्छा प्रदर्शन करने वाले पैटर्न "कंस्ट्रक्टर वातावरण के माध्यम से निजी डेटा" और "निजी डेटा एक नामकरण सम्मेलन के माध्यम से" थे। मेरे लिए सफारी ने वीकएप के लिए अच्छा प्रदर्शन किया लेकिन क्रोम इतना अच्छा नहीं है।

मुझे स्मृति प्रभाव का पता नहीं है, लेकिन "कंस्ट्रक्टर वातावरण" के लिए पैटर्न, जिसे कुछ लोगों ने चेतावनी दी थी कि एक प्रदर्शन मुद्दा बहुत अच्छा होगा।

4 बुनियादी पैटर्न हैं:

कंस्ट्रक्टर वातावरण के माध्यम से निजी डेटा

class Countdown {
    constructor(counter, action) {
        Object.assign(this, {
            dec() {
                if (counter < 1) return;
                counter--;
                if (counter === 0) {
                    action();
                }
            }
        });
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

कंस्ट्रक्टर वातावरण 2 के माध्यम से निजी डेटा

class Countdown {
    constructor(counter, action) {
        this.dec = function dec() {
            if (counter < 1) return;
            counter--;
            if (counter === 0) {
                action();
            }
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

एक नामकरण सम्मेलन के माध्यम से निजी डेटा

class Countdown {
    constructor(counter, action) {
        this._counter = counter;
        this._action = action;
    }
    dec() {
        if (this._counter < 1) return;
        this._counter--;
        if (this._counter === 0) {
            this._action();
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

WeakMaps के माध्यम से निजी डेटा

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

प्रतीकों के माध्यम से निजी डेटा

const _counter = Symbol('counter');
const _action = Symbol('action');

class Countdown {
    constructor(counter, action) {
        this[_counter] = counter;
        this[_action] = action;
    }
    dec() {
        if (this[_counter] < 1) return;
        this[_counter]--;
        if (this[_counter] === 0) {
            this[_action]();
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

4

मेरा मानना ​​है कि कंस्ट्रक्टर के अंदर क्लोजर का उपयोग करके 'दोनों दुनियाओं में सर्वश्रेष्ठ' प्राप्त करना संभव है। दो भिन्नताएं हैं:

सभी डेटा सदस्य निजी हैं

function myFunc() {
   console.log('Value of x: ' + this.x);
   this.myPrivateFunc();
}

function myPrivateFunc() {
   console.log('Enhanced value of x: ' + (this.x + 1));
}

class Test {
   constructor() {

      let internal = {
         x : 2,
      };
      
      internal.myPrivateFunc = myPrivateFunc.bind(internal);
      
      this.myFunc = myFunc.bind(internal);
   }
};

कुछ सदस्य निजी हैं

नोट: यह भर्ती बदसूरत है। यदि आप एक बेहतर समाधान जानते हैं, तो कृपया इस प्रतिक्रिया को संपादित करें।

function myFunc(priv, pub) {
   pub.y = 3; // The Test object now gets a member 'y' with value 3.
   console.log('Value of x: ' + priv.x);
   this.myPrivateFunc();
}

function myPrivateFunc() {
   pub.z = 5; // The Test object now gets a member 'z' with value 3.
   console.log('Enhanced value of x: ' + (priv.x + 1));
}

class Test {
   constructor() {
      
      let self = this;

      let internal = {
         x : 2,
      };
      
      internal.myPrivateFunc = myPrivateFunc.bind(null, internal, self);
      
      this.myFunc = myFunc.bind(null, internal, self);
   }
};


4

वास्तव में यह प्रतीकों और परदे के पीछे का उपयोग करना संभव है। आप वर्ग दायरे में प्रतीकों का उपयोग करते हैं और एक प्रॉक्सी में दो जाल सेट करते हैं: एक वर्ग प्रोटोटाइप के लिए ताकि Reflect.ownKeys (उदाहरण) या Object.getOwnPropertySymbols अपने प्रतीकों को दूर न करें, दूसरा एक स्वयं निर्माता के लिए है इसलिए जब new ClassName(attrs)बुलाया जाता है, तो लौटाए गए उदाहरण को इंटरसेप्ट किया जाएगा और स्वयं के गुणों के प्रतीकों को अवरुद्ध कर दिया जाएगा। यहाँ कोड है:

const Human = (function() {
  const pet = Symbol();
  const greet = Symbol();

  const Human = privatizeSymbolsInFn(function(name) {
    this.name = name; // public
    this[pet] = 'dog'; // private 
  });

  Human.prototype = privatizeSymbolsInObj({
    [greet]() { // private
      return 'Hi there!';
    },
    revealSecrets() {
      console.log(this[greet]() + ` The pet is a ${this[pet]}`);
    }
  });

  return Human;
})();

const bob = new Human('Bob');

console.assert(bob instanceof Human);
console.assert(Reflect.ownKeys(bob).length === 1) // only ['name']
console.assert(Reflect.ownKeys(Human.prototype).length === 1 ) // only ['revealSecrets']


// Setting up the traps inside proxies:
function privatizeSymbolsInObj(target) { 
  return new Proxy(target, { ownKeys: Object.getOwnPropertyNames });
}

function privatizeSymbolsInFn(Class) {
  function construct(TargetClass, argsList) {
    const instance = new TargetClass(...argsList);
    return privatizeSymbolsInObj(instance);
  }
  return new Proxy(Class, { construct });
}

Reflect.ownKeys()इस तरह काम करता है: Object.getOwnPropertyNames(myObj).concat(Object.getOwnPropertySymbols(myObj))इसलिए हमें इन वस्तुओं के लिए एक जाल की आवश्यकता है।


धन्यवाद, मैं प्रतीकों की कोशिश करूँगा :) उपरोक्त सभी उत्तरों से यह दुर्गम वर्ग सदस्य बनाने का सबसे सीधा तरीका लगता है :)
कोकोडको

4

यहां तक ​​कि टाइपस्क्रिप्ट भी नहीं कर सकता। उनके प्रलेखन से :

जब कोई सदस्य निजी रूप से चिह्नित होता है, तो उसे उसके वर्ग से बाहर तक नहीं पहुँचा जा सकता है। उदाहरण के लिए:

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

new Animal("Cat").name; // Error: 'name' is private;

लेकिन यह उनके खेल के मैदान पर फैल जाता है:

var Animal = (function () {
    function Animal(theName) {
        this.name = theName;
    }
    return Animal;
}());
console.log(new Animal("Cat").name);

इसलिए उनका "निजी" कीवर्ड अप्रभावी है।


2
खैर, यह अभी भी प्रभावी है क्योंकि यह आईडीई में "खराब" प्रोग्रामिंग को रोकता है। यह आपको दिखाता है कि आपको किन सदस्यों का उपयोग करना चाहिए और क्या नहीं करना चाहिए। मुझे लगता है कि यह निजी और सार्वजनिक उपयोग करने का मुख्य कारण है। (उदाहरण के लिए, जब आप C # को मशीन कोड में संकलित करते हैं, तो क्या निजी अभी भी निजी होगा? कौन जानता है?)। अन्य उत्तरों को पढ़ते समय, ऐसा लगता है कि @ सिंबल का उपयोग करना भी एक सदस्य को दुर्गम बना सकता है। लेकिन सिंबल्स को अभी भी कंसोल से पाया जा सकता है।
कोकोडको

क्या टाइपस्क्रिप्ट को जावास्क्रिप्ट में टाइपस्क्रिप्ट के ट्रांसपाइल के दौरान त्रुटि होती है? (जैसा कि टाइपिंग चेकिंग ट्रांसकैप समय पर होता है। कुछ रनटाइम प्राइवेट मैकेनिज्म के बजाय।)
एलजय

4

इस पार्टी में बहुत देर से आ रहा था लेकिन मैंने एक खोज में ओपी के सवाल को हिट कर दिया ... हां, आपके पास एक बंद में कक्षा की घोषणा को लपेटकर निजी गुण हो सकते हैं

इस कोडपेन में मेरे निजी तरीके कैसे हैं, इसका एक उदाहरण है । नीचे दिए गए स्निपेट में, सब्सक्राइबेबल क्लास में दो 'प्राइवेट' फंक्शन होते हैं processऔर processCallbacks। किसी भी गुण को इस तरीके से जोड़ा जा सकता है और बंद के उपयोग के माध्यम से उन्हें निजी रखा जाता है। IMO गोपनीयता एक दुर्लभ आवश्यकता है यदि चिंताएं अच्छी तरह से अलग हो जाती हैं और जब एक करीबी काम करता है तो जावास्क्रिप्ट को अधिक सिंटैक्स जोड़कर फूला हुआ बनने की आवश्यकता नहीं होती है।

const Subscribable = (function(){

  const process = (self, eventName, args) => {
    self.processing.set(eventName, setTimeout(() => processCallbacks(self, eventName, args)))};

  const processCallbacks = (self, eventName, args) => {
    if (self.callingBack.get(eventName).length > 0){
      const [nextCallback, ...callingBack] = self.callingBack.get(eventName);
      self.callingBack.set(eventName, callingBack);
      process(self, eventName, args);
      nextCallback(...args)}
    else {
      delete self.processing.delete(eventName)}};

  return class {
    constructor(){
      this.callingBack = new Map();
      this.processing = new Map();
      this.toCallbacks = new Map()}

    subscribe(eventName, callback){
      const callbacks = this.unsubscribe(eventName, callback);
      this.toCallbacks.set(eventName,  [...callbacks, callback]);
      return () => this.unsubscribe(eventName, callback)}  // callable to unsubscribe for convenience

    unsubscribe(eventName, callback){
      let callbacks = this.toCallbacks.get(eventName) || [];
      callbacks = callbacks.filter(subscribedCallback => subscribedCallback !== callback);
      if (callbacks.length > 0) {
        this.toCallbacks.set(eventName, callbacks)}
      else {
        this.toCallbacks.delete(eventName)}
      return callbacks}

    emit(eventName, ...args){
      this.callingBack.set(eventName, this.toCallbacks.get(eventName) || []);
      if (!this.processing.has(eventName)){
        process(this, eventName, args)}}}})();

मुझे यह दृष्टिकोण पसंद है क्योंकि यह चिंताओं को अच्छी तरह से अलग करता है और चीजों को वास्तव में निजी रखता है। निजी सामग्री में 'इस' को संदर्भित करने के लिए केवल नकारात्मक पक्ष 'स्वयं' (या कुछ इसी तरह) का उपयोग करने की आवश्यकता है।


4

मुझे लगता है कि बेंजामिन का जवाब शायद ज्यादातर मामलों के लिए सबसे अच्छा है जब तक कि भाषा मूल रूप से स्पष्ट रूप से निजी चर का समर्थन करती है।

हालाँकि, अगर किसी कारण से आपको पहुँच को रोकने की आवश्यकता होती है Object.getOwnPropertySymbols(), तो जिस विधि का उपयोग करने पर विचार किया जाता है वह एक अद्वितीय, गैर-विन्यास योग्य, गैर-प्रवर्तनीय, गैर-लिखने योग्य संपत्ति को संलग्न करना है जो निर्माण पर प्रत्येक वस्तु के लिए एक संपत्ति पहचानकर्ता के रूप में उपयोग किया जा सकता है। (जैसे कि एक अद्वितीय Symbol, यदि आपके पास पहले से कुछ अन्य अद्वितीय संपत्ति नहीं है id)। फिर बस उस पहचानकर्ता का उपयोग करके प्रत्येक ऑब्जेक्ट के 'निजी' चर का नक्शा रखें।

const privateVars = {};

class Something {
    constructor(){
        Object.defineProperty(this, '_sym', {
            configurable: false,
            enumerable: false,
            writable: false,
            value: Symbol()
        });

        var myPrivateVars = {
            privateProperty: "I'm hidden"
        };

        privateVars[this._sym] = myPrivateVars;

        this.property = "I'm public";
    }

    getPrivateProperty() {
        return privateVars[this._sym].privateProperty;
    }

    // A clean up method of some kind is necessary since the
    // variables won't be cleaned up from memory automatically
    // when the object is garbage collected
    destroy() {
        delete privateVars[this._sym];
    }
}

var instance = new Something();
console.log(instance.property); //=> "I'm public"
console.log(instance.privateProperty); //=> undefined
console.log(instance.getPrivateProperty()); //=> "I'm hidden"

यदि प्रदर्शन एक चिंता का विषय है, तो इस दृष्टिकोण का संभावित लाभ तेजी से पहुंच के समय का उपयोग कर रहा WeakMapहै ।


1
अगर मैं गलत हूं तो मुझे सुधारें, लेकिन क्या इस कोड में मेमोरी लीक नहीं होगी क्योंकि प्राइवेटवेयर अभी भी ऑब्जेक्ट के प्राइवेट वैरिएबल को स्टोर करेगा भले ही ऑब्जेक्ट पहले से ही नष्ट हो गया हो?
रसेल सैंटोस

@RussellSantos आप सही हैं, यह मानते हुए कि वस्तुओं को किसी बिंदु पर एकत्र किया जाने वाला कचरा होना चाहिए। उसे इंगित करने के लिए धन्यवाद। मेरे उदाहरण में मैंने एक destroy()विधि जोड़ी है जिसे किसी वस्तु को निकालने की आवश्यकता होने पर कोड का उपयोग करके बुलाया जाना चाहिए।
नैनोवेयर

4

हाँ पूरी तरह से कर सकते हैं, और बहुत आसानी से भी। यह कंस्ट्रक्टर में प्रोटोटाइप ऑब्जेक्ट ग्राफ को वापस करके आपके निजी चर और कार्यों को उजागर करने के द्वारा किया जाता है। यह कोई नई बात नहीं है, लेकिन इसके लालित्य को समझने के लिए थोड़ा js foo लें। इस तरह से वैश्विक स्कोप्ड या कमजोर वर्ग का उपयोग नहीं किया जाता है। यह भाषा में निर्मित प्रतिबिंब का एक रूप है। इस बात पर निर्भर करता है कि आप इसका लाभ कैसे उठाते हैं; एक या तो एक अपवाद को बाध्य कर सकता है जो कॉल स्टैक को बाधित करता है, या अपवाद को एक के रूप में दफन करता है undefined। यह नीचे प्रदर्शित किया गया है, और यहाँ इन विशेषताओं के बारे में अधिक पढ़ सकते हैं

class Clazz {
  constructor() {
    var _level = 1

    function _private(x) {
      return _level * x;
    }
    return {
      level: _level,
      public: this.private,
      public2: function(x) {
        return _private(x);
      },
      public3: function(x) {
        return _private(x) * this.public(x);
      },
    };
  }

  private(x) {
    return x * x;
  }
}

var clazz = new Clazz();

console.log(clazz._level); //undefined
console.log(clazz._private); // undefined
console.log(clazz.level); // 1
console.log(clazz.public(1)); //1
console.log(clazz.public2(2)); //2
console.log(clazz.public3(3)); //27
console.log(clazz.private(0)); //error


3
class Something {
  constructor(){
    var _property = "test";
    Object.defineProperty(this, "property", {
        get: function(){ return _property}
    });
  }
}

var instance = new Something();
console.log(instance.property); //=> "test"
instance.property = "can read from outside, but can't write";
console.log(instance.property); //=> "test"

2
यह केवल उत्तरों से बचने के लिए सबसे अच्छा है। यह बेहतर होगा यदि आप बता सकते हैं कि आपका कोड ओपी के सवाल का जवाब कैसे देता है
स्टीवर्ट_आर

यह वास्तव में निजी चर की तुलना में एक पठनीय चर बनाने का तरीका है। एक निजी चर बाहर तक पहुंच नहीं होना चाहिए। console.log(instance.property)आपको फेंक देना चाहिए या आपको अनिर्धारित नहीं करना चाहिए, न कि आपको "परीक्षण" वापस देना चाहिए।
ऊय्या

3

पिछले दो पोस्ट के समान एक और तरीका

class Example {
  constructor(foo) {

    // privates
    const self = this;
    this.foo = foo;

    // public interface
    return self.public;
  }

  public = {
    // empty data
    nodata: { data: [] },
    // noop
    noop: () => {},
  }

  // everything else private
  bar = 10
}

const test = new Example('FOO');
console.log(test.foo); // undefined
console.log(test.noop); // { data: [] }
console.log(test.bar); // undefined

2

अधिकांश उत्तर या तो कहते हैं कि यह असंभव है, या आपको एक WeakMap या Symbol का उपयोग करने की आवश्यकता है, जो ES6 विशेषताएं हैं जिन्हें संभवतः पॉलीफ़िल की आवश्यकता होगी। हालांकि एक और तरीका है! इसे देखें:

// 1. Create closure
var SomeClass = function() {
  // 2. Create `key` inside a closure
  var key = {};
  // Function to create private storage
  var private = function() {
    var obj = {};
    // return Function to access private storage using `key`
    return function(testkey) {
      if(key === testkey) return obj;
      // If `key` is wrong, then storage cannot be accessed
      console.error('Cannot access private properties');
      return undefined;
    };
  };
  var SomeClass = function() {
    // 3. Create private storage
    this._ = private();
    // 4. Access private storage using the `key`
    this._(key).priv_prop = 200;
  };
  SomeClass.prototype.test = function() {
    console.log(this._(key).priv_prop); // Using property from prototype
  };
  return SomeClass;
}();

// Can access private property from within prototype
var instance = new SomeClass();
instance.test(); // `200` logged

// Cannot access private property from outside of the closure
var wrong_key = {};
instance._(wrong_key); // undefined; error logged

मैं इस पद्धति को एक्सेसर पैटर्न कहता हूं । आवश्यक विचार यह है कि हमारे पास एक बंद , एक कुंजी है अंदर है, और हम एक निजी ऑब्जेक्ट (निर्माणकर्ता में) बनाते हैं जिसे केवल तभी एक्सेस किया जा सकता है जब आपके पास कुंजी हो

यदि आप रुचि रखते हैं, तो आप मेरे लेख में इसके बारे में अधिक पढ़ सकते हैं । इस पद्धति का उपयोग करके, आप प्रति ऑब्जेक्ट गुण बना सकते हैं जिसे क्लोजर के बाहर एक्सेस नहीं किया जा सकता है। इसलिए, आप उन्हें कंस्ट्रक्टर या प्रोटोटाइप में उपयोग कर सकते हैं, लेकिन कहीं और नहीं। मैंने इस पद्धति का कहीं भी उपयोग नहीं किया है, लेकिन मुझे लगता है कि यह वास्तव में शक्तिशाली है।


सवाल यह था कि ईएस 6 कक्षाओं में इसे कैसे प्राप्त किया जाए।
माइकल फ्रांज़ल

आप ES6 कक्षाओं में ठीक उसी विधि का उपयोग कर सकते हैं। ES6 कक्षाएं मुख्य रूप से केवल चीनी के कार्यों के शीर्ष पर हैं जैसे मैंने अपने उदाहरण में प्रस्तुत किया है। यह काफी संभव है कि मूल पोस्टर एक ट्रांसपिलर का उपयोग कर रहा है, जिस स्थिति में WeakMaps या Symbols को अभी भी पॉलीफिल की आवश्यकता होगी। मेरा जवाब परवाह किए बिना मान्य है।
गिटारिनो

2

एक निजी और सार्वजनिक इंटरफ़ेस और रचना के लिए समर्थन के साथ स्वच्छ और सरल 'वर्ग' समाधान के लिए इस उत्तर को देखें


2

मुझे एक बहुत ही सरल समाधान मिला, बस उपयोग करें Object.freeze()। बेशक समस्या यह है कि आप बाद में ऑब्जेक्ट में कुछ भी नहीं जोड़ सकते हैं।

class Cat {
    constructor(name ,age) {
        this.name = name
        this.age = age
        Object.freeze(this)
    }
}

let cat = new Cat('Garfield', 5)
cat.age = 6 // doesn't work, even throws an error in strict mode

यह सेटर विधि को भी निष्क्रिय कर देगा जैसेsetName(name) { this.name = name; }
ngakak

2

मैं इस पैटर्न का उपयोग करता हूं और यह हमेशा मेरे लिए काम करता है

class Test {
    constructor(data) {
        class Public {
            constructor(prv) {

                // public function (must be in constructor on order to access "prv" variable)
                connectToDb(ip) {
                    prv._db(ip, prv._err);
                } 
            }

            // public function w/o access to "prv" variable
            log() {
                console.log("I'm logging");
            }
        }

        // private variables
        this._data = data;
        this._err = function(ip) {
            console.log("could not connect to "+ip);
        }
    }

    // private function
    _db(ip, err) {
        if(!!ip) {
		    console.log("connected to "+ip+", sending data '"+this.data+"'");
			return true;
		}
        else err(ip);
    }
}



var test = new Test(10),
		ip = "185.167.210.49";
test.connectToDb(ip); // true
test.log(); // I'm logging
test._err(ip); // undefined
test._db(ip, function() { console.log("You have got hacked!"); }); // undefined


2

वास्तव में यह है संभव।
1. सबसे पहले, क्लास बनाएं और कंस्ट्रक्टर में दिए गए _publicफंक्शन को वापस करें ।
2. में कहा जाता है _publicसमारोह thisसंदर्भ (सभी निजी तरीकों और सहारा के लिए उपयोग पाने के लिए) , और से सभी तर्कों constructor (कि पारित किया जाएगा new Names())
3. _publicसमारोह के दायरे में भी (_this) Namesका उपयोग करने के साथ वर्ग है this) निजी Namesवर्ग का संदर्भ

class Names {
  constructor() {
    this.privateProperty = 'John';
    return _public(this, arguments);
  }
  privateMethod() { }
}

const names = new Names(1,2,3);
console.log(names.somePublicMethod); //[Function]
console.log(names.publicProperty); //'Jasmine'
console.log(names.privateMethod); //undefined
console.log(names.privateProperty); //undefind

function _public(_this, _arguments) {
  class Names {
    constructor() {
      this.publicProperty = 'Jasmine';
      _this.privateProperty; //"John";
      _this.privateMethod; //[Function]
    }

    somePublicMethod() {
      _this.privateProperty; //"John";
      _this.privateMethod; //[Function]
    }

  }
  return new Names(..._arguments);
}

2

आप इसे https://www.npmjs.com/package/pStreet-members पर आज़मा सकते हैं

यह पैकेज सदस्यों को उदाहरण के द्वारा बचाएगा।

const pvt = require('private-members');
const _ = pvt();

let Exemplo = (function () {    
    function Exemplo() {
        _(this).msg = "Minha Mensagem";
    }

    _().mensagem = function() {
        return _(this).msg;
    }

    Exemplo.prototype.showMsg = function () {
        let msg = _(this).mensagem();
        console.log(msg);
    };

    return Exemplo;
})();

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