2012-01-02 13 views
8

हूलो! यह मेरा पहला सवाल है!जावास्क्रिप्ट मॉड्यूल पैटर्न - संरक्षित सदस्य?

मैं मॉड्यूल पैटर्न डौग Crockford और अन्य लोगों द्वारा पदोन्नत के साथ प्रयोग कर रहा हूँ। अब तक इसके साथ बहुत खुश हैं, लेकिन मैं एक निश्चित विरासत पैटर्न को संभालने का सबसे अच्छा तरीका के बारे में थोड़ा अनिश्चित हूं।

मैं, हालांकि मेरे वास्तविक इरादा कैनवास में एक टाइल आधारित खेल के लिए वस्तुओं बनाने के लिए है यह बिल्ली और स्तनपायी का उपयोग कर एक नंगे हड्डियों मामले के लिए नीचे उबला हुआ है।

लेकिन यहाँ एक ब्राउज़र चेतावनी का उपयोग कर मेरे नंगे हड्डियों 'जानवर' मामला है:

var ZOO = ZOO || {}; 
// 
ZOO.mammal = function() { 
    "use strict"; 
    var voice = "squeak.mp3", // default mammal sound 
     utter = function() { 
     window.alert(this.voice); 
     }; 
// 
    // public interface 
    return { 
     utter: utter, 
     voice: voice 
    }; 
}; 
// 
ZOO.cat = function() { 
    "use strict"; 
    // hook up ancestor 
    var thisCat = ZOO.mammal(); 
    thisCat.voice = "miaw.mp3"; 
    return thisCat; 
}; 
// 
var felix = ZOO.cat(); 
felix.utter(); 

क्या मुझे इस दृष्टिकोण के बारे में परेशान करती है कि मैं voice एक सार्वजनिक संपत्ति बनाने के लिए इतना है कि बिल्ली संशोधित कर सकते हैं पड़ा है है।

क्या मैं सच में चाहते हैं 'सुरक्षित' दृश्यता की तरह कुछ (जावा, ActionScript आदि से), ताकि cat इसे संशोधित करने में सक्षम होने felix के उपयोग के साथ किसी को भी बिना voice को संशोधित कर सकते हैं।

क्या कोई समाधान है?

उत्तर

14

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

कुछ तरीके तरह का जावास्क्रिप्ट में संरक्षित गुण मिल रहे हैं, लेकिन वे आवश्यक रूप से बहुत मुहावरेदार नहीं हैं:

var ZOO = ZOO || {}; 

ZOO.mammal = function (protectedInfo) { 
    "use strict"; 
    protectedInfo = protectedInfo || {}; 
    protectedInfo.voice = "squeak.mp3"; 

    // public interface 
    return { 
     utter: function() { 
     alert(protectedInfo.voice); 
     } 
    }; 
}; 

ZOO.cat = function() { 
    "use strict"; 

    var protectedInfo = {}; 
    // hook up ancestor 
    var thisCat = ZOO.mammal(protectedInfo); 

    protectedInfo.voice = "miaw.mp3"; 
    return thisCat; 
}; 

यहाँ एक live demo

1

Sidesteping गैर जवाब है। अगर मैं तुम्हें थे मैं पहली बार दृढ़ता का उपयोग करते हुए सार्वजनिक संपत्तियों की परंपरा एक अंडरस्कोर (पूर्व .: _voice) के साथ आरंभ गोपनीयता निरूपित करने के लिए विचार किया जाएगा या तो

  1. । यह बहुत सरल है और गतिशील भाषाओं के बीच एक मानक है।

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

+0

मुझे लगता है कि डगलस क्रॉकफ़ोर्ड आपसे असहमत है: 'अब तक हमने देखा है कि विरासत पैटर्न की एक कमजोरी यह है कि हमें कोई गोपनीयता नहीं मिलती है। किसी ऑब्जेक्ट के सभी गुण दिखाई दे रहे हैं। हमें कोई निजी चर नहीं मिलता है और कोई निजी तरीका नहीं मिलता है। कभी-कभी इससे कोई फर्क नहीं पड़ता, लेकिन कभी-कभी यह बहुत मायने रखता है। निराशा में, कुछ अनौपचारिक प्रोग्रामर ने गोपनीयता का एक पैटर्न अपनाया है। अगर उनके पास एक संपत्ति है जो वे निजी बनाना चाहते हैं, तो वे इसे एक अजीब नाम देते हैं .... सौभाग्य से, हमारे पास मॉड्यूल पैटर्न के अनुप्रयोग में एक बेहतर विकल्प है। '[क्रॉकफोर्ड 52] –

+0

गोपनीयता का दावा करना सिर्फ " निराशा से पैदा हुआ "- यह बहुत ही सरल और straigtfoward है और प्रोटोटाइप विरासत जेएस मूल रूप से समर्थन करता है और ऑब्जेक्ट क्लोनिंग और प्रतिबिंब जैसी चीजों के साथ अच्छी तरह से खेलता है (इसलिए इसे अभी तक खारिज न करें)। वैसे भी, मैंने जवाब लिखने का वास्तविक कारण यह इंगित करना था कि आपको * आवश्यक रूप से * संरक्षित सदस्यों की आवश्यकता नहीं है (या शायद पहले स्थान पर विरासत) – hugomg

+0

यह सच है - ऐसा करने से आप प्रोटोटाइप विरासत का उपयोग करने से रोकते हैं। –

1

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

मैं सिर्फ इस SitePoint article से उद्धृत कर रहा हूँ:

जोड़ना संरक्षित सदस्य

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

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

जावास्क्रिप्ट में ऐसे संरक्षित सदस्य नहीं हैं, लेकिन हम प्रभावी ढंग से डेटा अस्थायी रूप से सार्वजनिक बनाकर बना सकते हैं। विस्तार और निजीकरण - - प्राप्त करने के लिए इस है, मुझे पहले दो प्रमुख कार्य को लागू करते हैं जो हमने उपयोगिता-कार्यों के हिस्से के रूप को परिभाषित करेंगे वस्तु:

var utils = { 
    extend : function(root, props) { 
    for(var key in props) { 
     if(props.hasOwnProperty(key)) { 
     root[key] = props[key]; 
     } 
    } return root; 
    }, 
    privatise : function(root, prop) { 
    var data = root[prop]; 
    try { delete root[prop]; } catch(ex) { root[prop] = null; } 
    return data; 
    } 
}; 

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

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

var MyModule = (function() { 
    var myProtectedData = 909; 
    var utils = { 
    extend : function(root, props) { }, 
    privatise : function(root, prop) { } 
    }; 
    this.myPublicData = 42; 
    return utils.extend(this, { myProtectedData : myProtectedData, utils : utils }); 
})(); 

आप कैसे हम एक संस्करण का उपयोग कर रहे देख सकते हैं खुलासा मॉड्यूल पैटर्न, केवल सार्वजनिक सदस्यों को वापस करने के लिए, लेकिन संरक्षित सदस्यों को अच्छी तरह से वापस करने के लिए। तो इस बिंदु पर हमारे पास तीन सार्वजनिक सदस्य हैं: MyModule.my संरक्षित डेटा, MyModule.utils और MyModule.myPublicData।

अब यहाँ पिछले मॉड्यूल निर्दिष्ट सार्वजनिक सदस्यों वापस निजी चर पर प्रतिलिपि बनाने के निजीकरण फ़ंक्शन का उपयोग करता है जो का एक उदाहरण है, और उसके बाद अपने सार्वजनिक संदर्भ हटा दें:

var MyModule = (function() { 
    var myProtectedData = this.utils.privatise(this, 'myProtectedData'); 
    var utils = this.utils.privatise(this, 'utils'); 
    return this; 
}).apply(MyModule); 

और संरक्षित एक बार यह हो जाने पर सदस्यों को उनके ऑब्जेक्ट्स के अंदर बंद कर दिया गया है, जो दोनों मॉड्यूल के लिए निजी रूप से उपलब्ध हैं, लेकिन अब उनके बाहर से उपलब्ध नहीं हैं।

ध्यान दें कि निजीकरण समारोह वस्तु और संपत्ति-कुंजी के लिए अलग तर्क होने पर निर्भर करता है, क्योंकि जावास्क्रिप्ट में वस्तुओं संदर्भ द्वारा पारित कर रहे हैं। तो रूट MyModule का संदर्भ है, और जब हम कुंजी से निर्दिष्ट संपत्ति से हटाते हैं, तो हम संदर्भित ऑब्जेक्ट से संपत्ति को हटा रहे हैं।

लेकिन अगर यह इस तरह था:

privatise : function(root) { 
    var data = root; 
    try { delete root; } catch(ex) { root = null; } return data; 
} 

और इस तरह कहा जाता है:

var myProtectedData = this.utils.privatise(this.myProtectedData); 
फिर

सार्वजनिक सदस्यों को हटाया नहीं जा होगा - समारोह बस, संदर्भ को नष्ट नहीं होगा संपत्ति यह संदर्भित करता है।

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

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