2011-11-07 5 views
11

में कैसे बनाने के लिए संरक्षित वस्तु गुण वहाँ एक जावास्क्रिप्ट पैटर्न जो की नकल करता है कि आप क्या सी की तरह ++ भाषाओं में देखने की तरह "संरक्षित" वस्तु गुण है ??जावास्क्रिप्ट

असल में, मैं एक ऑब्जेक्ट ए बनाना चाहता हूं जिसमें कई "संरक्षित" ऑब्जेक्ट गुण हैं जिन्हें केवल ऑब्जेक्ट ए के प्रोटोटाइप से परिभाषित विधियों से एक्सेस किया जा सकता है यानी गैर- ए के नमूने के तरीकों

उदाहरण के लिए, आदर्श तो जैसा होगा:

function A(){ 
    var prop1 = 1;  
} 

A.prototype.myFunc = function(){ 
    var newVar = this.prop1; //newVar now is equivalent to 1 
} 

var instanceOfA = new A(); 
var newVar2 = instanceOfA.prop1; //error given as prop1 is "protected"; hence undefined in this case 

BTW - मैं निजी संपत्तियों तक पहुँचने सदस्य समारोह अभी भी सार्वजनिक है के बाद से विशेषाधिकार प्राप्त सदस्य कार्यों के पैटर्न नहीं करना चाहती। http://javascript.crockford.com/private.html

+2

नहीं ............ –

+6

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

+0

बीटीडब्ल्यू, प्रोटोटाइप ऑब्जेक्ट्स को बढ़ाया जा सकता है (वे सील नहीं किए जाते हैं) - प्रोटोटाइप ऑब्जेक्ट में नए तरीकों को जोड़ने के लिए घुसपैठियों को कुछ भी नहीं रोकता है। इसलिए, प्रोटोटाइप विधियों के माध्यम से केवल एक संपत्ति सुलभ होने के बावजूद सुरक्षित नहीं होगा (भले ही यह संभव हो)। –

उत्तर

12

कोई ऑब्जेक्ट प्रॉपर्टी नहीं है जिसे केवल A के प्रोटोटाइप तरीकों से एक्सेस किया जा सकता है और A की गैर-प्रोटोटाइप विधियों से नहीं। इस भाषा में उस प्रकार की सुविधा नहीं है और मुझे इसे लागू करने के लिए किसी भी काम-आसपास/हैक से अवगत नहीं है।

Doug Crockford's methods का उपयोग करके, आप सदस्य गुण बना सकते हैं जिन्हें केवल पूर्व परिभाषित गैर-प्रोटोटाइप विधियों (कन्स्ट्रक्टर में परिभाषित) से ही एक्सेस किया जा सकता है। इसलिए, यदि आप केवल तरीकों में से एक पूर्वनिर्धारित सेट तक पहुँच को सीमित करने की कोशिश कर रहे हैं, यह है कि पूरा होगा। इसके अलावा, मुझे लगता है कि आप भाग्य से बाहर हैं।

आप अन्य विचारों चाहते हैं, तो आप शायद अधिक सहायता प्राप्त करता है, तो आप क्या आप वास्तव में कितना किसी अन्य भाषा में एक सुविधा का अनुकरण करने के बजाय अपने कोड में पूरा करने के लिए कोशिश कर रहे हैं के बारे में अधिक का वर्णन होगा। जावास्क्रिप्ट इतना सी तुलना में अलग है ++ है कि यह समस्या की जरूरतों के बजाय शुरू कुछ सी ++ सुविधा के लिए एक सादृश्य खोजने की कोशिश करने के लिए बेहतर है। Emulating protected members in JavaScript

यह तरीकों और एक वस्तु के गुणों के protected पहुंच का स्तर emulates:

4

यह शायद आप के लिए क्या देख रहे हैं।

+0

मैं सहमत हूं। वह डॉग क्रॉकफ़ोर्ड लेख सदस्य चर गोपनीयता के विकल्पों के 'निश्चित विवरण' है। यह उपलब्ध है। वे कुछ हद तक हैक हैं क्योंकि आधिकारिक तौर पर भाषा द्वारा समर्थित प्रत्येक सदस्य चर सार्वजनिक है, लेकिन आप बंद करने का उपयोग करके विभिन्न तरीकों से गोपनीयता प्राप्त कर सकते हैं। – jfriend00

+2

@ एरिक्सन ओपी ने कहा कि उन्हें विशेषाधिकार प्राप्त कार्यों में कोई दिलचस्पी नहीं है ... –

+3

मैं यह भी इंगित करना चाहूंगा कि जब आप उस लेख में क्रॉकफोर्ड के पास क्या कर सकते हैं, तो इसका मतलब यह नहीं है कि आपको यह करना चाहिए। भाषा एक्स में कार्यक्रम जैसे आप भाषा एक्स के लिए प्रोग्रामिंग कर रहे हैं, भाषा वाई नहीं। उस ने कहा, कुछ वैध उपयोग हैं (! एएचईएम!) निजी चर (मुझे लगता है कि मेरा मुंह सिर्फ यह कहकर ब्लेड है) जेएस में, लेकिन मैं इसमें नहीं जाऊंगा, क्योंकि उन उपयोगों के लिए क्लास डिज़ाइन के साथ वास्तव में कुछ भी करने की ज़रूरत नहीं है। –

9

आपको Javascript में ऐसा नहीं कर सकते हैं:

+0

क्या आप समझा सकते हैं कि मुझे -1 क्यों मिला? जो मैंने लिखा वह जेएस में पूरी तरह से सच है। आप जेएस में संरक्षित गुण नहीं बना सकते हैं। इसके लिए और कुछ नहीं है। –

+4

यह सच है, अन्यथा नाटक करने का प्रयास करना इस आसान तथ्य को स्वीकार करने से कहीं अधिक हानिकारक है। – Esailija

+5

{{उद्धरण वांछित}} – Offirmo

0

अपनी वेबसाइट पर Maks द्वारा प्रस्तावित वैकल्पिक हल पर एक नजर डालें।

5

मैं संरक्षित सदस्यों बनाने के लिए एक रास्ता मिल गया। वजह मैं आधार निर्माता कहते हैं और एक ही समय में संरक्षित सदस्यों के साथ एक ऑब्जेक्ट:

var protected = BaseClass.call(this); 

यहाँ एक उदाहरण:

function SignedIntegerArray(size) 
{ 
    var public = this; 
    var protected = {}; 

    // private property: 
    var _maxSize = 10000; 
    // protected property: 
    protected.array = []; 
    // public property: 
    public.Length = size; 

    if(!isInteger(size) || size < 0 || size > _maxSize) { throw "argument exception"; } 
    for(var index = 0; index != size; index++) { protected.array[index] = 0; } 

    // private method: 
    function isInteger(i) { return i == i + 0 && i == ~~i; } 
    // protected method: 
    protected.checkIndex = function(index) { return index >= 0 && index < size; } 
    // public methods: 
    public.SetValue = function(index, value) { if(protected.checkIndex(index) && isInteger(value)) { protected.array[index] = value; } }; 
    public.GetValue = function(index) { if(protected.checkIndex(index)) { return protected.array[index]; } else { throw "index out of range exception"; }} 

    return protected; 
} 

function FloatArray(size, range) 
{ 
    var public = this; 
    var protected = SignedIntegerArray.call(this, size); // call the base constructor and get the protected members 

    // new private method, "isInteger" is hidden... 
    function isFloat(argument) { return argument != ~~argument; } 
    // ...but "checkIndex" is accessible 
    public.SetValue = function(index, value) { if(protected.checkIndex(index) && isFloat(value) && value >= public.MinValue && value <= public.MaxValue) { protected.array[index] = value; } }; 

    // new public properties: 
    public.MinValue = -range; 
    public.MaxValue = range; 

    return protected; // for sub-classes 
} 

function newObject(className, args) { return new function() { className.apply(this, args)}} // you need to use function.call or function.apply to initialize an object. otherwise the protected-object is empty. 
window.addEventListener("load", function() 
{ 
    var o = newObject(FloatArray, [4, 50.0]); 
    o.SetValue(3, 2.1); 
    console.log(o.GetValue(3)); 
    console.log(o.Length); // property from the base-class 
}); 
+0

इस दृष्टिकोण का नकारात्मक पक्ष यह है कि आप प्रत्येक आंतों के लिए स्मृति बर्बाद करते हैं, क्योंकि प्रत्येक उदाहरण में प्रोटोटाइप पर विधियों का पुन: उपयोग करने के बजाय डुप्लीकेट फ़ंक्शन होते हैं। इसलिए 100 उदाहरणों के लिए आपके पास कन्स्ट्रक्टर में परिभाषित कार्यों के 100 संस्करण हैं, जबकि प्रोटोटाइप विधियों के साथ आपके पास केवल एक फ़ंक्शन इंस्टेंस होगा। इसे ऐसी विधि के लिए देखें जो स्मृति को बर्बाद नहीं करता है: https://github.com/philipwalton/mozart – trusktr

2
function ClassA(init) 
{ 
    var protected = {}; 
    protected.prop = init * 10; 
    if(this.constructor != ClassA) { return protected; } 
} 

function ClassB() 
{ 
    var protected = ClassA.call(this, 5); //console.log(protected.prop); 
} 

//var a = new ClassA(123); 
//var b = new ClassB(); 
1

मैं जवाब देने के लिए एक रास्ता खोजने के लिए दिलचस्पी थी अपने सवाल, और यहां मैं क्या करने में सक्षम था।

var ProtectedHandler = (function() { 
    /// <Sumarry> 
    /// Tool to handle the protected members of each inheritance. 
    /// </Summary> 
    /// <param name="current">Current protected variable.</param> 
    /// <param name="args">The arguments variable of the object.</param> 
    /// <param name="callback">The function to initialise the variable in the 'object'.</param> 
    /// <param name="isParent">Is this the ultimate base object.</param> 
    function ProtectedHandler(current, args, callback, isParent) { 
     this.child = getChild(args); 
     if (callback) 
      this.callback = callback; 

     if (isParent) 
      this.overrideChild(current); 
    } 

    // Get the ProtectedHandler from the arguments 
    var getChild = function (args) { 
     var child = null; 
     if (args.length > 0 && (child = args[args.length - 1]) && child.constructor === ProtectedHandler) 
      return child; 
    }; 

    // Chain Initialise the protected variable of the object and its inheritances. 
    ProtectedHandler.prototype.overrideChild = function (newValue) { 
     if (this.callback != null) { 
      this.callback(newValue); 
     } 
     if (this.child != null) { 
      this.child.overrideChild(newValue); 
     } 
    }; 

    // Static function to create a new instance of the protectedHandler object. 
    ProtectedHandler.handle = function (protected, arguments, callback, isParent) { 
     return new ProtectedHandler(protected, arguments, callback, isParent); 
    }; 

    return ProtectedHandler; 
})(); 

यह सहायक आप एकाधिक विरासत को संभालने के लिए अनुमति देगा:

आप इस सहायक की आवश्यकता होगी। यह चाल संरक्षित चर को मूल वस्तु से आपकी नई वस्तु (बच्चे) में कॉपी करना है।

आप यह काम कर रहा साबित करने के लिए, यहाँ एक उदाहरण है:

// That's the default extends function from typescript (ref: http://www.typescriptlang.org/) 
var __extends = this.__extends || function (d, b) { 
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; 
    function __() { this.constructor = d; } 
    __.prototype = b.prototype; 
    d.prototype = new __(); 
}; 

var BaseClass = (function() {   
    function BaseClass() { 
     // Members 
     var private = {}, 
      protected = {}, 
      public = this; 

     // Constructor 
     ProtectedHandler.handle(protected, arguments, function() { 
      protected.type = "BaseClass"; 
     }, true); 

     // Methods 
     protected.saySomething = function() { 
      return "Hello World"; 
     }; 

     public.getType = function() { 
      return protected.type; 
     }; 
    } 

    return BaseClass; 
})(); 



var Person = (function (_super) { 
    __extends(Person, _super); 

    function Person(name) { 
     // Members 
     var private = {}, 
      protected = {}, 
      public; 

     // Constructor 
     _super.call(public = this, ProtectedHandler.handle(protected, arguments, function (p) { 
      protected = p; //This is required to copy the object from its base object. 
      protected.name = name; 
      protected.type = "Person"; 
     })); 

     //Method 
     public.getName = function() { 
      return protected.name; 
     }; 

     public.saySomething = function() { 
      return protected.saySomething(); 
     }; 
    } 
    return Person; 
})(BaseClass); 


var Child = (function (_super) { 
    __extends(Child, _super); 

    function Child(name) { 
     // Members 
     var private = {}, 
      protected = {}, 
      public; 

     // Constructor 
     _super.call(public = this, name, ProtectedHandler.handle(protected, arguments, function (p) { 
      protected = p; //This is required to copy the object from its base object. 
      protected.type = "Child"; 
     })); 

     //Method 
     public.setName = function (value) { 
      return protected.name = value; 
     }; 
    } 
    return Child; 
})(Person); 

और यहाँ है परीक्षण:

var testBase = new BaseClass(); 
testBase.getType(); //"BaseClass" 
testBase.saySomething; //undefined 

var testPerson = new Person("Nic"); 
testPerson.getType(); //"Person" 
testPerson.saySomething(); //"Hello World" 
testPerson.name; //undefined 
testPerson.getName() //"Nic" 
testPerson.setName; //undefined 

var testChild = new Child("Bob"); 
testChild.getType(); //"Child" 
testChild.saySomething(); //"Hello World" 
testChild.name; //undefined 
testChild.getName(); //"Bob" 
testChild.setName("George"); 
testChild.getName(); //"George" 
1

एक पैटर्न है कि मैं पसंद करने के लिए है कि एक ही तरह से काम नहीं करता आ गए हैं नहीं है क्योंकि अधिकांश भाषाओं में संरक्षित पहुंच होती है, लेकिन यह समान लाभ प्रदान करती है।

मूल रूप से, गुणों के लिए बंद करने के लिए एक निर्माता विधि का उपयोग करें, और उसके बाद उस विधि को उदार पहुंच के साथ "पूर्ण" ऑब्जेक्ट बनाएं और साथ ही साथ "सीमित" ऑब्जेक्ट को अधिक सीमित पहुंच के साथ बनाएं। खुली वस्तु को पूर्ण ऑब्जेक्ट की संपत्ति में रखें, और उस पूर्ण ऑब्जेक्ट को कॉलर पर वापस कर दें।

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

एक काल्पनिक उदाहरण ...

// Ring employs a typical private/public pattern while 
// RingEntry employs a private/exposed/full access pattern. 

function buildRing(size) { 
    var i 
    , head = buildRingEntry(0) 
    , newEntry; 
    ; 
    head.setNext(head); 
    for(i = size - 1; i ; i--) { 
    newEntry = buildRingEntry(i); 
    newEntry.setNext(head.getNext()); 
    head.setNext(newEntry); 
    } 
    function getHead() { return head.exposed; } 
    return { 
     getHead : getHead 
    } 
} 

function buildRingEntry(index) { 
    var next 
    , exposed 
    ; 
    function getIndex() { return index; } 
    function setNext(newNext) { next = newNext; } 
    function getNextFullEntry() { return next; } 
    function getNextExposedEntry() { return next.exposed; } 
    exposed = { 
     getIndex : getIndex 
    , getNext : getNextExposedEntry 
    }; 
    return { 
     getIndex : getIndex 
    , setNext : setNext 
    , getNext : getNextFullEntry 
    , exposed : exposed 
    }; 
} 

अगर हम का उपयोग करने वाले 4 प्रविष्टियों ring = buildRing(4); की एक अंगूठी का निर्माण करने के लिए, तो ring.getHead().getIndex() हमें देता है 0, ring.getHead().getNext().getIndex() हमें 1 देता है, ring.getHead().getNext().getNext().getIndex() हमें 2 देता है, आदि

अगर हम ring.getHead().setNext({}) या ring.getHead().getNext().setNext({}) निष्पादित करने का प्रयास करते हैं, तो हमें एक त्रुटि मिलती है क्योंकि setNext एक खुला प्रविष्टि ऑब्जेक्ट की संपत्ति नहीं है।

चेतावनी:

के बाद से इस पैटर्न है कि तरीकों प्रत्येक नई वस्तु के लिए एक नया बंद में फिर से निर्माण के परिवार में है, यह परिस्थितियाँ होती हैं जिनमें इन्स्टेन्शियशन की एक बहुत ही उच्च मात्रा की जरूरत हो सकती लिए उपयुक्त नहीं है।

+0

ध्यान दें कि इस पैटर्न का पूर्ण ऑब्जेक्ट के लिए कन्स्ट्रक्टर फ़ंक्शन के साथ भी उपयोग किया जा सकता है। बस कन्स्ट्रक्टर बॉडी के भीतर से 'इस' की उजागर संपत्ति बनाएं और असाइन करें। –

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