2009-01-27 24 views
17

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

a=function(text) 
{ 
    var b=text; 
    if (!arguments.callee.prototype.get) 
     arguments.callee.prototype.get=function() 
    { 
     return b; 
    } 
    else 
     alert('already created!'); 
} 

var c=new a("test"); // creates prototype instance of getter 
var d=new a("ojoj"); // alerts already created 
alert(c.get())  // alerts test 
alert(d.get())  // alerts test from context of creating prototype function :(

जैसा कि आप देखते हैं कि मैंने प्रोटोटाइप गेटटर बनाने की कोशिश की है। किस लिए? खैर, अगर आप कुछ इस तरह लिखना:

a=function(text) 
{ 
    var b=text; 
    this.getText=function(){ return b} 
} 

... सब कुछ ठीक हो जाना चाहिए .. लेकिन वास्तव में हर बार जब मैं वस्तु बना सकते हैं - मैं gettext समारोह स्मृति का उपयोग करता है बनाएँ। मैं एक प्रोटोटाइपिकल फ़ंक्शन मेमोरी में लेटना चाहता हूं जो वही करेगा ... कोई विचार?

संपादित करें:

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

someFunc = function() 
{ 
    var store = new Array(); 
    var guid=0; 
    var someFunc = function(text) 
    { 
    this.__guid=guid; 
    store[guid++]=text; 
    } 

    someFunc.prototype.getValue=function() 
    { 
    return store[this.__guid]; 
    } 

    return someFunc; 
}() 

a=new someFunc("test"); 
b=new someFunc("test2"); 

alert(a.getValue()); 
alert(b.getValue()); 
+0

यह [अन्य प्रश्न] (http://stackoverflow.com/questions/436120) –

उत्तर

28

जावास्क्रिप्ट पारंपरिक रूप से संपत्ति छिपाने के लिए एक तंत्र प्रदान नहीं करता है ('निजी सदस्य')।

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

बेशक, इस के आसपास काम करने के तरीके हैं, लेकिन मैं यह सिफारिश नहीं होगा:

Foo = (function() { 
    var store = {}, guid = 0; 

    function Foo() { 
     this.__guid = ++guid; 
     store[guid] = { bar : 'baz' }; 
    } 

    Foo.prototype.getBar = function() { 
     var privates = store[this.__guid]; 
     return privates.bar; 
    }; 

    Foo.prototype.destroy = function() { 
     delete store[this.__guid]; 
    }; 

    return Foo; 
})(); 

यह आपके Foo उदाहरण से अन्य वस्तु अलग में 'निजी' गुण स्टोर करेगा। ऑब्जेक्ट के साथ किए जाने के बाद destroy() पर कॉल करना सुनिश्चित करें: अन्यथा, आपने अभी मेमोरी लीक बनाई है।


संपादित 2015/12/01: ECMAScript6 बेहतर वेरिएंट कि मैनुअल वस्तु विनाश संभव आवश्यकता नहीं है, एक WeakMap या अधिमानतः एक Symbol का उपयोग करके जैसे बनाता है, एक बाहरी दुकान पूरी तरह के लिए की जरूरत से परहेज:

var Foo = (function() { 
    var bar = Symbol('bar'); 

    function Foo() { 
     this[bar] = 'baz'; 
    } 

    Foo.prototype.getBar = function() { 
     return this[bar]; 
    }; 

    return Foo; 
})(); 
+0

का डुप्लिकेट जैसा प्रतीत होता है इसका मतलब यह नहीं है कि जब भी मैं नया Foo() कहता हूं तो मैं पूरी नई फ़ंक्शन ऑब्जेक्ट बनाता हूं ?? – Wilq32

+0

कुछ ठीक नहीं दिखता है ... फू क्लास के 2 उदाहरण होने पर यह कैसे संभालता है? –

+0

ओह, मैं देखता हूं ... "स्टोर" पूरी कक्षा द्वारा साझा किया जाता है, लेकिन स्टोर में प्रविष्टि प्रति उदाहरण है। –

2

तरीके "निजी" के सदस्यों को एक्सेस नहीं कर सकता के रूप में वे जावास्क्रिप्ट में मौजूद हैं; आपको किसी तरह का विशेषाधिकार प्राप्त एक्सेसर चाहिए। चूंकि आप get घोषित कर रहे हैं, जहां यह b को स्पष्ट रूप से देख सकता है, यह हमेशा b सृजन पर था जो वापस करेगा।

2

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

  • अब निर्माता में किसी भी सेटअप प्रदर्शन करने के लिए
  • एक सार्वजनिक GUID उदाहरणों पर
  • जोड़ा कुछ वाक्यात्मक चीनी

अनिवार्य रूप से चाल यहाँ स्टोर करने के लिए की जरूरत है हटाया की जरूरत संबंधित ऑब्जेक्ट को एक्सेस करने के लिए कुंजी ऑब्जेक्ट को स्वयं कुंजी के रूप में उपयोग करना है। आम तौर पर सादे वस्तुओं के साथ यह संभव नहीं है क्योंकि उनकी चाबियाँ तार होनी चाहिए। हालांकि, मैं इस तथ्य का उपयोग करके इसे पूरा करने में सक्षम था कि अभिव्यक्ति ({} === {})false लौटाती है। दूसरे शब्दों में तुलना ऑपरेटर अद्वितीय ऑब्जेक्ट उदाहरणों के बीच समझ सकता है।

Foo = (function() { 
    var instances = [], privates = []; 

    // private object accessor function 
    function _(instance) { 
     var index = instances.indexOf(instance), privateObj; 

     if(index == -1) { 
      // Lazily associate instance with a new private object 
      instances.push(instance); 
      privates.push(privateObj = {}); 
     } 
     else { 
      // A privateObject has already been created, so grab that 
      privateObj = privates[index]; 
     } 
     return privateObj; 
    } 

    function Foo() { 
     _(this).bar = "This is a private bar!"; 
    } 

    Foo.prototype.getBar = function() { 
     return _(this).bar; 
    }; 

    return Foo; 
})(); 

आप _ समारोह ऊपर दिखाई देंगे:

लंबी कहानी संक्षेप में, हम उदाहरणों और उनके संबद्ध निजी वस्तुओं बनाए रखने के लिए दो सरणियों उपयोग कर सकते हैं। निजी ऑब्जेक्ट की पकड़ पकड़ने के लिए यह एक्सेसर फ़ंक्शन है। यह आलसी काम करता है, इसलिए यदि आप इसे एक नए उदाहरण के साथ कहते हैं, तो यह फ्लाई पर एक नई निजी वस्तु बनाएगा।

आप हर वर्ग के लिए _ कोड नकल नहीं करना चाहते हैं, तो आप एक कारखाने समारोह के अंदर यह लपेटकर द्वारा इस का समाधान कर सकते हैं:

function createPrivateStore() { 
    var instances = [], privates = []; 

    return function (instance) { 
     // Same implementation as example above ... 
    }; 
} 

अब आप इसे करने के लिए सिर्फ एक ही प्रत्येक वर्ग के लिए लाइन कम कर सकते हैं :

var _ = createPrivateStore(); 

फिर से, आप इस समाधान का उपयोग के रूप में यह मेमोरी लीक बना सकते हैं बहुत सावधान होने के लिए अगर आप को लागू करने और एक कामकाज को नष्ट फोन नहीं है जब आवश्यक हो।

-1

मैंने प्रोटोटाइप श्रृंखला पर निजी विधियों को सक्षम करने के लिए एक नई लाइब्रेरी बनाई है। https://github.com/TremayneChrist/ProtectJS

उदाहरण:

var MyObject = (function() { 

    // Create the object 
    function MyObject() {} 

    // Add methods to the prototype 
    MyObject.prototype = { 

    // This is our public method 
    public: function() { 
     console.log('PUBLIC method has been called'); 
    }, 

    // This is our private method, using (_) 
    _private: function() { 
     console.log('PRIVATE method has been called'); 
    } 
    } 

    return protect(MyObject); 

})(); 

// Create an instance of the object 
var mo = new MyObject(); 

// Call its methods 
mo.public(); // Pass 
mo._private(); // Fail 
0

व्यक्तिगत रूप से, मैं क्या वास्तव में नहीं GUID के साथ समाधान की तरह है, क्योंकि यह डेवलपर बलों की दुकान के अलावा यह घोषणा करने के लिए और निर्माता में यह बढ़ाने के लिए। बड़े जावास्क्रिप्ट एप्लिकेशन डेवलपर्स में ऐसा करना भूल सकता है जो काफी त्रुटि प्रवण है।

मुझे इस तथ्य के कारण पीटर के उत्तर को बहुत पसंद है क्योंकि आप संदर्भ (इस) का उपयोग कर निजी सदस्यों तक पहुंच सकते हैं। लेकिन एक चीज जो मुझे काफी परेशान करती है वह यह तथ्य है कि निजी सदस्यों तक पहुंच ओ (एन) जटिलता में की जाती है। वास्तव में सरणी में किसी ऑब्जेक्ट की अनुक्रमणिका ढूंढना एक रैखिक एल्गोरिदम है। विचार करें कि आप इस पैटर्न का उपयोग ऐसे ऑब्जेक्ट के लिए करना चाहते हैं जो 10000 बार उत्पन्न हो। फिर जब भी आप किसी निजी सदस्य तक पहुंचना चाहते हैं तो आप 10000 उदाहरणों के माध्यम से फिर से शुरू हो सकते हैं।

ओ (1) जटिलता में निजी स्टोर तक पहुंचने के लिए, मार्गदर्शकों का उपयोग करने के अलावा कोई अन्य तरीका नहीं है।

createPrivateStore = function() { 
var privates = {}, guid = 0; 

return function (instance) { 
    if (instance.__ajxguid__ === undefined) { 
     // Lazily associate instance with a new private object 
     var private_obj = {}; 
     instance.__ajxguid__ = ++guid; 
     privates[instance.__ajxguid__] = private_obj; 
     return private_obj; 
    } 

    return privates[instance.__ajxguid__]; 
} 

}

चाल यहाँ पर विचार करना है: लेकिन आदेश GUID घोषणा और incrementation साथ-व्यवस्था निजी संग्रह तक पहुंचने संदर्भ का उपयोग करने के परेशान करने के लिए नहीं में मैं इस प्रकार पीटर्स कारखाने पैटर्न संशोधित वस्तुओं है कि ajxguid संपत्ति की जरूरत नहीं है अभी तक संभाला नहीं कर रहे हैं कि। वास्तव में, पहली बार स्टोर तक पहुंचने से पहले कोई व्यक्ति संपत्ति को मैन्युअल रूप से सेट कर सकता है, लेकिन मुझे लगता है कि कोई जादुई समाधान नहीं है।

2
कुछ ES6 प्रौद्योगिकियों को अपनाने आधुनिक ब्राउज़रों के साथ

, आप WeakMap का उपयोग GUID समस्या को हल पाने के लिए कर सकते हैं। यह IE11 में और ऊपर काम करता है:

// Scope private vars inside an IIFE 
var Foo = (function() { 
    // Store all the Foos, and garbage-collect them automatically 
    var fooMap = new WeakMap(); 

    var Foo = function(txt) { 
     var privateMethod = function() { 
      console.log(txt); 
     }; 
     // Store this Foo in the WeakMap 
     fooMap.set(this, {privateMethod: privateMethod}); 
    } 

    Foo.prototype = Object.create(Object.prototype); 
    Foo.prototype.public = function() { 
     fooMap.get(this).p(); 
    } 
    return Foo; 
}()); 

var foo1 = new Foo("This is foo1's private method"); 
var foo2 = new Foo("This is foo2's private method"); 
foo1.public(); // "This is foo1's private method" 
foo2.public(); // "This is foo2's private method" 

WeakMap बाद इसे हटा या क्षेत्र से बाहर जाता है, और के बाद से यह कुंजी के रूप में वस्तुओं का उपयोग करता है, आप के लिए GUIDs संलग्न करने की जरूरत नहीं है हो जाता है किसी भी Foo के लिए संदर्भ संग्रहीत नहीं करेगा आपकी वस्तु

+0

+1, लेकिन यदि आप ES6 के साथ जा रहे हैं, तो क्यों नहीं [प्रतीकों] का उपयोग करें (https://developer.mozilla.org/en-US/docs/Web/जावास्क्रिप्ट/संदर्भ/ग्लोबल_ऑब्जेक्ट्स/प्रतीक) – Christoph

+0

@ क्रिस्टोफ: क्योंकि ऑब्जेक्ट से प्रतीक जुड़े हुए हैं और आप उन्हें 'ऑब्जेक्ट.getOwnPropertySymbols() 'का उपयोग करके प्राप्त कर सकते हैं। आपने शायद यह पहले से ही पाया है ... – jimasun

संबंधित मुद्दे