चूँकि आपने एक समान प्रश्न पूछा था , इसलिए इसे चरण दर चरण लेते हैं। यह थोड़ा लंबा है, लेकिन इसे लिखने में मैंने जितना खर्च किया है, उससे बहुत अधिक समय बच सकता है:
प्रॉपर्टी एक OOP फीचर है जो क्लाइंट कोड के साफ पृथक्करण के लिए बनाया गया है। उदाहरण के लिए, कुछ ई-शॉप में आपके पास इस तरह की वस्तुएं हो सकती हैं:
function Product(name,price) {
this.name = name;
this.price = price;
this.discount = 0;
}
var sneakers = new Product("Sneakers",20); // {name:"Sneakers",price:20,discount:0}
var tshirt = new Product("T-shirt",10); // {name:"T-shirt",price:10,discount:0}
फिर अपने ग्राहक कोड (ई-शॉप) में, आप अपने उत्पादों में छूट जोड़ सकते हैं:
function badProduct(obj) { obj.discount+= 20; ... }
function generalDiscount(obj) { obj.discount+= 10; ... }
function distributorDiscount(obj) { obj.discount+= 15; ... }
बाद में, ई-शॉप के मालिक को एहसास हो सकता है कि छूट 80% से अधिक नहीं हो सकती है। अब आपको ग्राहक कोड में छूट संशोधन की हर जगह खोजने और एक पंक्ति जोड़ने की आवश्यकता है
if(obj.discount>80) obj.discount = 80;
फिर ई-शॉप के मालिक अपनी रणनीति को और बदल सकते हैं, जैसे "यदि ग्राहक पुनर्विक्रेता है, तो अधिकतम छूट 90% हो सकती है" । और आपको फिर से कई स्थानों पर परिवर्तन करने की आवश्यकता है और साथ ही आपको इन पंक्तियों को बदलने के लिए याद रखना होगा जब भी रणनीति बदली जाती है। यह एक खराब डिजाइन है। इसीलिए एनकैप्सुलेशन OOP का मूल सिद्धांत है। अगर कंस्ट्रक्टर इस तरह था:
function Product(name,price) {
var _name=name, _price=price, _discount=0;
this.getName = function() { return _name; }
this.setName = function(value) { _name = value; }
this.getPrice = function() { return _price; }
this.setPrice = function(value) { _price = value; }
this.getDiscount = function() { return _discount; }
this.setDiscount = function(value) { _discount = value; }
}
तो फिर तुम बस को बदल सकते हैं getDiscount
( एक्सेसर ) और setDiscount
( mutator ) तरीकों। समस्या यह है कि अधिकांश सदस्य सामान्य चर की तरह व्यवहार करते हैं, बस डिस्काउंट के लिए यहां विशेष देखभाल की आवश्यकता होती है। लेकिन अच्छे डिजाइन के लिए कोड को एक्स्टेंसिबल रखने के लिए हर डेटा मेंबर की इनकैप्सुलेशन की जरूरत होती है। तो आपको बहुत सारे कोड जोड़ने की आवश्यकता है जो कुछ भी नहीं करता है। यह एक खराब डिज़ाइन, एक बॉयलरप्लेट एंटीपैटर्न भी है । कभी-कभी आप केवल फ़ील्ड्स को बाद में तरीकों के लिए रिफलेक्टर नहीं कर सकते हैं (नाइयों कोड बड़े हो सकते हैं या कुछ तृतीय-पक्ष कोड पुराने संस्करण पर निर्भर हो सकते हैं), इसलिए बॉयलरप्लेट यहां कम बुराई है। लेकिन फिर भी, यह बुराई है। इसीलिए कई भाषाओं में गुणों का परिचय दिया गया। आप मूल कोड रख सकते हैं, बस छूट के सदस्य को एक संपत्ति में बदल सकते हैंget
और set
ब्लॉक:
function Product(name,price) {
this.name = name;
this.price = price;
//this.discount = 0; // <- remove this line and refactor with the code below
var _discount; // private member
Object.defineProperty(this,"discount",{
get: function() { return _discount; },
set: function(value) { _discount = value; if(_discount>80) _discount = 80; }
});
}
// the client code
var sneakers = new Product("Sneakers",20);
sneakers.discount = 50; // 50, setter is called
sneakers.discount+= 20; // 70, setter is called
sneakers.discount+= 20; // 80, not 90!
alert(sneakers.discount); // getter is called
अंतिम लेकिन एक पंक्ति पर ध्यान दें: सही छूट मूल्य के लिए जिम्मेदारी ग्राहक कोड (ई-शॉप परिभाषा) से उत्पाद परिभाषा में स्थानांतरित की गई थी। उत्पाद अपने डेटा सदस्यों को लगातार बनाए रखने के लिए जिम्मेदार है। अच्छा डिजाइन है (मोटे तौर पर कहा जाता है) अगर कोड हमारे विचारों के समान काम करता है।
गुणों के बारे में इतना। लेकिन जावास्क्रिप्ट शुद्ध ऑब्जेक्ट-ओरिएंटेड भाषाओं जैसे C # से अलग है और सुविधाओं को अलग तरह से कोड करता है:
C # में , फ़ील्ड को गुणों में बदलना एक ब्रेकिंग परिवर्तन है , इसलिए यदि आपके कोड को अलग-अलग संकलित क्लाइंट में उपयोग किया जा सकता है , तो सार्वजनिक फ़ील्ड को ऑटो-कार्यान्वित गुणों के रूप में कोडित किया जाना चाहिए ।
जावास्क्रिप्ट में , मानक गुण (ऊपर वर्णित गेट्टर और सेटर के साथ डेटा सदस्य) एक्सेसर डिस्क्रिप्टर द्वारा परिभाषित किए गए हैं (आपके प्रश्न में लिंक में)। विशेष रूप से, आप डेटा डिस्क्रिप्टर का उपयोग कर सकते हैं (ताकि आप एक ही प्रॉपर्टी पर मूल्य और सेट का उपयोग न कर सकें ):
- एक्सेसर डिस्क्रिप्टर = गेट + सेट (ऊपर उदाहरण देखें)
- प्राप्त एक समारोह होना चाहिए; संपत्ति को पढ़ने में इसका वापसी मूल्य उपयोग किया जाता है; यदि निर्दिष्ट नहीं किया गया है, तो डिफ़ॉल्ट अपरिभाषित है , जो एक फ़ंक्शन की तरह व्यवहार करता है जो अपरिभाषित देता है
- सेट एक फ़ंक्शन होना चाहिए; इसका मान संपत्ति के मूल्य को निर्दिष्ट करने में आरएचएस से भरा है; यदि निर्दिष्ट नहीं है, तो डिफ़ॉल्ट अपरिभाषित है , जो एक खाली फ़ंक्शन की तरह व्यवहार करता है
- डेटा डिस्क्रिप्टर = मान + लेखन (नीचे उदाहरण देखें)
- मान डिफ़ॉल्ट अपरिभाषित ; यदि लेखन योग्य , विन्यास योग्य और गणना योग्य (नीचे देखें) सत्य हैं, तो संपत्ति एक साधारण डेटा फ़ील्ड की तरह व्यवहार करती है
- लेखन योग्य - डिफ़ॉल्ट असत्य ; यदि सही नहीं है , तो संपत्ति केवल पढ़ी जाती है; लिखने का प्रयास त्रुटि के बिना अनदेखा है *!
दोनों विवरणक में ये सदस्य हो सकते हैं:
- विन्यास योग्य - डिफ़ॉल्ट गलत ; यदि सही नहीं है, तो संपत्ति को हटाया नहीं जा सकता है; हटाने का प्रयास त्रुटि के बिना अनदेखा है *!
- enumerable - default false ; अगर यह सच है, तो इसमें इसकी पुनरावृत्ति होगी
for(var i in theObject)
; यदि गलत है, तो इसे पुनरावृत्त नहीं किया जाएगा, लेकिन यह अभी भी सार्वजनिक रूप से सुलभ है
* जब तक सख्त मोड में नहीं होता है - उस स्थिति में JS टाइप टाइप के साथ निष्पादन बंद कर देता है जब तक कि इसे ट्राइ -कैच ब्लॉक में न पकड़ा जाए
इन सेटिंग्स को पढ़ने के लिए, उपयोग करें Object.getOwnPropertyDescriptor()
।
उदाहरण के द्वारा जानें:
var o = {};
Object.defineProperty(o,"test",{
value: "a",
configurable: true
});
console.log(Object.getOwnPropertyDescriptor(o,"test")); // check the settings
for(var i in o) console.log(o[i]); // nothing, o.test is not enumerable
console.log(o.test); // "a"
o.test = "b"; // o.test is still "a", (is not writable, no error)
delete(o.test); // bye bye, o.test (was configurable)
o.test = "b"; // o.test is "b"
for(var i in o) console.log(o[i]); // "b", default fields are enumerable
यदि आप क्लाइंट कोड को धोखा देने की अनुमति नहीं देना चाहते हैं, तो आप ऑब्जेक्ट को तीन स्तरों तक सीमित कर सकते हैं:
- Object.preventExtensions (yourObject) नए गुणों को अपने Object में जोड़ने से रोकता है ।
Object.isExtensible(<yourObject>)
जाँच करने के लिएउपयोगकरें कि क्या विधि का उपयोग वस्तु पर किया गया था। रोकथाम उथली है (नीचे पढ़ें)।
- Object.seal (yourObject) ऊपर के समान और गुणों को हटाया नहीं जा सकता (प्रभावी रूप
configurable: false
से सभी गुणों के लिएसेट)। Object.isSealed(<yourObject>)
ऑब्जेक्ट पर इस सुविधा का पता लगाने के लिएउपयोग करें। सील उथली है (नीचे पढ़ें)।
- ऑब्जेक्ट.फ्रीज (आपका ऑबजेक्ट) जैसा कि ऊपर दिया गया है और गुणों को नहीं बदला जा सकता है (प्रभावी रूप
writable: false
से डेटा डिस्क्रिप्टर के साथ सभी गुणों परसेटहोता है)। सेटर की लिखने योग्य संपत्ति प्रभावित नहीं होती है (क्योंकि इसमें एक नहीं है)। फ्रीज उथला है : इसका मतलब है कि अगर संपत्ति वस्तु है, तो इसके गुण जमे हुए नहीं हैं (यदि आप चाहें, तो आपको "डीप फ्रीज" जैसा कुछ करना चाहिए, डीप कॉपी - क्लोनिंग के समान)। इसकाObject.isFrozen(<yourObject>)
पता लगाने के लिएउपयोग करें।
अगर आपको सिर्फ कुछ पंक्तियां ही मजेदार लगीं तो आपको इससे परेशान होने की जरूरत नहीं है। लेकिन अगर आप एक गेम को कोड करना चाहते हैं (जैसा कि आपने लिंक किए गए प्रश्न में उल्लेख किया है), तो आपको वास्तव में अच्छे डिजाइन की परवाह करनी चाहिए। एंटीपैटर्न और कोड गंध के बारे में कुछ करने की कोशिश करें । यह आपको ओह जैसी स्थितियों से बचने में मदद करेगा , मुझे अपने कोड को पूरी तरह से फिर से लिखने की आवश्यकता है! यदि आप बहुत कोड करना चाहते हैं, तो यह आपको निराशा के महीनों को बचा सकता है। सौभाग्य।