paint-brush
स्रोत कोड का अध्ययन कैसे करें: Express.js में ऑब्जेक्ट प्रोटोटाइप और मिक्सिनद्वारा@luminix
200 रीडिंग

स्रोत कोड का अध्ययन कैसे करें: Express.js में ऑब्जेक्ट प्रोटोटाइप और मिक्सिन

द्वारा Lumin-ix11m2024/08/19
Read on Terminal Reader

बहुत लंबा; पढ़ने के लिए

सोर्स कोड का अध्ययन निस्संदेह आपके डेवलपर करियर की दिशा बदल सकता है। सतह के नीचे सिर्फ़ एक स्तर पर देखने से ही आप ज़्यादातर औसत डेवलपर्स से अलग हो सकते हैं। यह सीरीज़ इसी बारे में है: API से संतुष्ट न होना, बल्कि उससे आगे बढ़कर, इन टूल्स को फिर से बनाना सीखना। AI हाइप की इस दुनिया में औसत से बाहर निकलना ही एक डेवलपर को औसत से कहीं ज़्यादा मूल्यवान बनाता है!
featured image - स्रोत कोड का अध्ययन कैसे करें: Express.js में ऑब्जेक्ट प्रोटोटाइप और मिक्सिन
Lumin-ix HackerNoon profile picture
0-item
1-item

सोर्स कोड का अध्ययन निस्संदेह आपके डेवलपर करियर की दिशा बदल सकता है। सतह के नीचे सिर्फ़ एक स्तर पर देखने से ही आप ज़्यादातर औसत डेवलपर्स से अलग हो सकते हैं।


यह निपुणता की ओर पहला कदम है!


यहाँ एक व्यक्तिगत कहानी है: एक AI/ML स्टार्टअप में मेरे वर्तमान काम में, टीम यह पता नहीं लगा पाई कि विज़ुअलाइज़ेशन के लिए सर्वर से फ्रंटएंड तक Neo4j डेटा कैसे लाया जाए, और उन्हें 12 घंटे में एक प्रेजेंटेशन देना था। मुझे एक फ्रीलांसर के रूप में लाया गया था, और आप स्पष्ट रूप से घबराहट देख सकते थे। समस्या यह थी कि Neo4j द्वारा लौटाया गया डेटा विज़ुअलाइज़ेशन टूल, neo4jd3 द्वारा अपेक्षित सही प्रारूप में नहीं था।


कल्पना करें: Neo4jd3 एक त्रिभुज की अपेक्षा करता है, और Neo4j एक वर्ग लौटाता है। यह एक असंगत बेमेल है!


neo4jd3


हम जल्द ही मास्टर्ड में जावास्क्रिप्ट और नियो4जे के साथ ग्राफ डेटा साइंस कर सकते हैं! यह छवि पुरानी यादों को ताजा करती है।


केवल दो विकल्प थे: संपूर्ण Neo4j बैकएंड को फिर से तैयार करना या Neo4jd3 के स्रोत कोड का अध्ययन करना, अपेक्षित प्रारूप का पता लगाना, और फिर वर्ग को त्रिभुज में बदलने के लिए एक एडाप्टर बनाना।


 neo4jd3 <- adapter <- Neo4j 

एडाप्टर अर्थात



मेरा मस्तिष्क स्रोत कोड पढ़ने में लग गया, और मैंने एक एडाप्टर बनाया: neo4jd3-ts


 import createNeoChart, { NeoDatatoChartData } from "neo4jd3-ts";


एडाप्टर NeoDatatoChartData है, और बाकी सब इतिहास है। मैंने इस सबक को दिल से लिया, और जब भी मुझे मौका मिलता है, मैं हर उस टूल में एक स्तर नीचे चला जाता हूँ जिसका मैं उपयोग करता हूँ। यह इतना प्रचलित हो गया है कि कभी-कभी मैं दस्तावेज़ भी नहीं पढ़ता।


इस दृष्टिकोण ने मेरे करियर को बहुत बदल दिया। मैं जो कुछ भी करता हूँ वह जादू जैसा लगता है। कुछ ही महीनों में, मैं महत्वपूर्ण सर्वर माइग्रेशन और प्रोजेक्ट्स का नेतृत्व कर रहा था, यह सब इसलिए क्योंकि मैंने सोर्स की ओर एक कदम बढ़ाया था।


यह श्रृंखला इसी बारे में है: API से संतुष्ट न होना, बल्कि उससे आगे बढ़कर, इन उपकरणों को फिर से बनाना सीखना। AI हाइप की इस दुनिया में औसत से बाहर निकलना ही एक डेवलपर को औसत से कहीं ज़्यादा मूल्यवान बनाता है!


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


चूंकि मैं मुख्यतः एक बैकएंड इंजीनियर हूं (हां, पूर्ण स्टैक, लेकिन 90% समय बैकएंड को संभालता हूं), इसलिए शुरुआत करने के लिए Express.js से बेहतर कोई टूल नहीं है।


मेरा अनुमान है कि आपको प्रोग्रामिंग का अनुभव है और प्रोग्रामिंग के मूल सिद्धांतों की अच्छी समझ है! आपको एक उन्नत शुरुआती के रूप में वर्गीकृत किया जा सकता है।


बुनियादी बातों को पढ़ाते समय सोर्स कोड सीखना/सिखाना वाकई बहुत कठिन और थकाऊ होगा। आप इस सीरीज़ में शामिल हो सकते हैं, लेकिन यह कठिन होने की उम्मीद करें। मैं सब कुछ कवर नहीं कर सकता, लेकिन मैं जितना हो सके उतना प्रयास करूँगा।


यह लेख एक कारण से एक्सप्रेस से पहले का है: मैंने एक बहुत छोटी लाइब्रेरी, मर्ज-डिस्क्रिप्टर्स , जिस पर एक्सप्रेस निर्भर है, को कवर करने का निर्णय लिया, जिसके, जब मैं यह लिख रहा हूँ, 27,181,495 डाउनलोड हैं और कोड की मात्र 26 लाइनें हैं।


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

स्थापित करना

आगे बढ़ने से पहले, सुनिश्चित करें कि आपके सिस्टम में एक्सप्रेस सोर्स कोड और मर्ज-डिस्क्रिप्टर मौजूद हैं। इस तरह, आप इसे IDE में खोल सकते हैं और मैं आपको लाइन नंबर के साथ बता सकता हूँ कि हम कहाँ देख रहे हैं।


एक्सप्रेस एक बहुत बड़ी लाइब्रेरी है। हम दूसरे टूल पर जाने से पहले कुछ लेखों में जितना संभव हो उतना कवर करेंगे।


अपने IDE में एक्सप्रेस स्रोत खोलें, अधिमानतः लाइन नंबर के साथ, lib फ़ोल्डर पर जाएँ, और express.js फ़ाइल, प्रविष्टि फ़ाइल खोलें।


लाइन 17 पर हमारी पहली लाइब्रेरी है:


 var mixin = require('merge-descriptors');


उपयोग पंक्ति 42 और 43 में है:


 mixin(app, EventEmitter.prototype, false); mixin(app, proto, false);


इससे पहले कि हम यह पता लगाएँ कि यहाँ क्या हो रहा है, हमें एक कदम पीछे हटकर जावास्क्रिप्ट में ऑब्जेक्ट्स के बारे में बात करनी होगी, डेटा संरचना से परे। हम कंपोजिशन, इनहेरिटेंस, प्रोटोटाइप और मिक्सिन पर चर्चा करेंगे - जो इस लेख का शीर्षक है।

जावास्क्रिप्ट ऑब्जेक्ट

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


ऑब्जेक्ट, डेटा और व्यवहार का एक समामेलन है, जो ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग (OOP) के मूल में है। मज़ेदार तथ्य: जावास्क्रिप्ट में लगभग सब कुछ एक ऑब्जेक्ट है।


 const person = { // data name: "Jane", age: 0, // behavior grow(){ this.age += 1; } };

person ऑब्जेक्ट में उद्घाटन और समापन ब्रेसिज़ के बीच की हर चीज़ को ऑब्जेक्ट की अपनी प्रॉपर्टीज़ कहा जाता है। यह महत्वपूर्ण है।


स्वयं के गुण वे हैं जो सीधे वस्तु पर होते हैं। name , age और grow person के स्वयं के गुण हैं।


यह महत्वपूर्ण है क्योंकि प्रत्येक जावास्क्रिप्ट ऑब्जेक्ट में एक prototype प्रॉपर्टी होती है। आइए उपरोक्त ऑब्जेक्ट को फ़ंक्शन ब्लूप्रिंट में एनकोड करें ताकि हम गतिशील रूप से person ऑब्जेक्ट बना सकें।


 function createNewPerson(name, age){ this.name = name; this.age = age; } createNewPerson.prototype.print = function(){ console.log(`${this.name} is ${this.age}`); }; const john = new createNewPerson("John", 32);

प्रोटोटाइप वह तरीका है जिससे जावास्क्रिप्ट ऑब्जेक्ट अन्य ऑब्जेक्ट से गुण और विधियाँ प्राप्त करते हैं। Own Properties और Prototype के बीच अंतर तब होता है जब किसी ऑब्जेक्ट पर प्रॉपर्टी एक्सेस की जाती है:


 john.name; // access


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


एक प्रोटोटाइप ऑब्जेक्ट अपने स्वयं के प्रोटोटाइप के माध्यम से किसी अन्य ऑब्जेक्ट से विरासत प्राप्त कर सकता है। इसे प्रोटोटाइप चेन कहा जाता है।


 console.log(john.hasOwnProperty('name')); // true console.log(john.hasOwnProperty('print')); // false, it's in the prototype


हालाँकि, print john पर काम करता है:


 john.print(); // "John is 32"


यही कारण है कि जावास्क्रिप्ट को प्रोटोटाइप-आधारित भाषा के रूप में परिभाषित किया गया है। हम प्रोटोटाइप के साथ सिर्फ़ गुण और विधियाँ जोड़ने के अलावा और भी बहुत कुछ कर सकते हैं, जैसे कि विरासत।


विरासत की "हेलो वर्ल्ड" स्तनधारी ऑब्जेक्ट है। आइए इसे जावास्क्रिप्ट के साथ फिर से बनाएँ।


 // our Mammal blueprint function Mammal(name) { this.name = name; } Mammal.prototype.breathe = function() { console.log(`${this.name} is breathing.`); };


जावास्क्रिप्ट में, Object ऑब्जेक्ट के अंदर एक स्थिर फ़ंक्शन होता है:


 Object.create();


यह {} और new functionBlueprint के समान ही एक ऑब्जेक्ट बनाता है, लेकिन अंतर यह है कि create एक प्रोटोटाइप को इनहेरिट करने के लिए पैरामीटर के रूप में ले सकता है।


 // we use a cat blueprint function here (implemented below) Cat.prototype = Object.create(Mammal.prototype); // correction after we inherited all the properties Cat.prototype.constructor = Cat;


अब Cat में Mammal में पाई जाने वाली breathe विधि होगी, लेकिन जानने वाली महत्वपूर्ण बात यह है कि Cat अपने प्रोटोटाइप के रूप में Mammal ओर इशारा कर रही है।

स्पष्टीकरण:

  1. स्तनधारी ब्लूप्रिंट : हम सबसे पहले Mammal फ़ंक्शन को परिभाषित करते हैं और इसके प्रोटोटाइप में breathe विधि जोड़ते हैं।


  2. कैट इनहेरिटेंस : हम Cat फ़ंक्शन बनाते हैं और Cat.prototype को Object.create(Mammal.prototype) पर सेट करते हैं। यह Cat प्रोटोटाइप को Mammal से इनहेरिट करता है, लेकिन यह constructor पॉइंटर को Mammal में बदल देता है।


  3. कंस्ट्रक्टर को सही करना : हम Cat.prototype.constructor Cat पर वापस इंगित करने के लिए सही करते हैं, यह सुनिश्चित करते हुए कि Mammal से विधियों को इनहेरिट करते समय Cat ऑब्जेक्ट अपनी पहचान बनाए रखता है। अंत में, हम Cat में एक meow विधि जोड़ते हैं।


यह दृष्टिकोण Cat ऑब्जेक्ट को Mammal (जैसे breathe ) और इसके स्वयं के प्रोटोटाइप (जैसे meow ) दोनों से विधियों तक पहुंचने की अनुमति देता है।


हमें इसे ठीक करने की ज़रूरत है। आइए पूरा उदाहरण बनाएं:


 function Cat(name, breed) { this.name = name; this.breed = breed; } Cat.prototype = Object.create(Mammal.prototype); // cat prototype pointing to mammal // correction after we inherited all the properties Cat.prototype.constructor = Cat; // we are re-pointing a pointer, the inherited properties are still there Cat.prototype.meow = function() { console.log(`${this.name} is meowing.`); };


Cat.prototype.constructor = Cat समझने के लिए, आपको पॉइंटर्स के बारे में जानना होगा। जब हम Object.create के साथ Mammal से इनहेरिट करते हैं, तो यह हमारे Cat प्रोटोटाइप के पॉइंटर को Mammal में बदल देता है, जो गलत है। हम अभी भी चाहते हैं कि हमारा Cat अपना अलग व्यक्तित्व हो, भले ही उसका पैरेंट Mammal हो।


इसलिए हमें इसे ठीक करना होगा।


इस उदाहरण में, Cat प्रोटोटाइप चेन का उपयोग करके Mammal से विरासत में प्राप्त होता है। Cat ऑब्जेक्ट breathe और meow दोनों विधियों तक पहुँच सकता है।


 const myCat = new Cat("Misty", "Ragdoll"); myCat.breathe(); // Misty is breathing. myCat.meow(); // Misty is meowing.


हम स्तनपायी से विरासत में प्राप्त एक कुत्ता भी बना सकते हैं:


 function Dog(name, breed) { this.name = name; this.breed = breed; } Dog.prototype = Object.create(Mammal.prototype); Dog.prototype.constructor = Dog; Dog.prototype.bark = function() { console.log(`${this.name} is barking.`); }; const myDog = new Dog('Buddy', 'Golden Retriever'); myDog.breathe(); // Buddy is breathing. myDog.bark(); // Buddy is barking.


हमने बुनियादी शास्त्रीय विरासत बनाई है, लेकिन यह महत्वपूर्ण क्यों है? मुझे लगा कि हम स्रोत कोड को कवर कर रहे थे!


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


वंशानुक्रम का विकल्प वस्तु संयोजन है, जो दो या अधिक वस्तुओं को लेकर उन्हें एक साथ मिलाकर एक "सुपर" वस्तु बनाता है।


मिक्सिन ऑब्जेक्ट को इनहेरिटेंस का उपयोग किए बिना अन्य ऑब्जेक्ट से विधियाँ उधार लेने की अनुमति देते हैं। वे असंबंधित ऑब्जेक्ट के बीच व्यवहार साझा करने के लिए उपयोगी हैं।


यही हमारा पहला अन्वेषण है: merge-descriptors लाइब्रेरी, जिसे हमने पहले कवर करने का वादा किया था।

मर्ज-डिस्क्रिप्टर मॉड्यूल

हम पहले ही देख चुके हैं कि एक्सप्रेस में इसका उपयोग कहाँ और कैसे किया जाता है। अब हम इसे ऑब्जेक्ट कंपोजिशन के लिए जानते हैं।


पंक्ति 17 में हमारी पहली लाइब्रेरी है:


 var mixin = require('merge-descriptors');


उपयोग पंक्ति 42 और 43 में है:


 mixin(app, EventEmitter.prototype, false); mixin(app, proto, false);


जो हम जानते हैं, उसके आधार पर हम पहले ही यह निष्कर्ष निकाल सकते हैं कि mixin EventEmitter.prototype और proto app नामक ऑब्जेक्ट में संयोजित कर रहा है।


जब हम एक्सप्रेस के बारे में बात करना शुरू करेंगे तो हम app पर आएंगे।


यह merge-descriptors के लिए संपूर्ण स्रोत कोड है:


 'use strict'; function mergeDescriptors(destination, source, overwrite = true) { if (!destination) { throw new TypeError('The `destination` argument is required.'); } if (!source) { throw new TypeError('The `source` argument is required.'); } for (const name of Object.getOwnPropertyNames(source)) { if (!overwrite && Object.hasOwn(destination, name)) { // Skip descriptor continue; } // Copy descriptor const descriptor = Object.getOwnPropertyDescriptor(source, name); Object.defineProperty(destination, name, descriptor); } return destination; } module.exports = mergeDescriptors;


शुरुआत से ही, हमेशा देखें कि फ़ंक्शन का उपयोग कैसे किया जाता है और यह कौन से पैरामीटर लेता है:


 // definition mergeDescriptors(destination, source, overwrite = true) // usage var mixin = require('merge-descriptors'); mixin(app, EventEmitter.prototype, false); mixin(app, proto, false);


App हमारा गंतव्य है। हम जानते हैं कि mixin का मतलब ऑब्जेक्ट कंपोजिशन है। मोटे तौर पर, यह पैकेज जो कर रहा है वह स्रोत ऑब्जेक्ट को गंतव्य ऑब्जेक्ट में कंपोज़ कर रहा है, जिसमें ओवरराइट करने का विकल्प भी है।


अधिलेखन, धारणा के अनुसार, यदि app (गंतव्य) में एक सटीक गुण है, तो स्रोत में भी वही गुण है, true अधिलेखन पर, अन्यथा उस गुण को अछूता छोड़ दें और छोड़ दें।


हम जानते हैं कि ऑब्जेक्ट में एक ही गुण दो बार नहीं हो सकता। कुंजी-मूल्य युग्मों (ऑब्जेक्ट) में, कुंजियाँ अद्वितीय होनी चाहिए।

एक्सप्रेस के साथ, अधिलेखित false है।


निम्नलिखित बुनियादी हाउसकीपिंग है, हमेशा अपेक्षित त्रुटियों को संभालें:


 if (!destination) { throw new TypeError('The `destination` argument is required.'); } if (!source) { throw new TypeError('The `source` argument is required.'); }


यहाँ से यह दिलचस्प हो जाता है: पंक्ति 12.


 for (const name of Object.getOwnPropertyNames(source)) {


ऊपर से, हम जानते हैं कि OwnProperty क्या अर्थ है, इसलिए getOwnPropertyNames स्पष्ट अर्थ है स्वयं की संपत्तियों की कुंजी प्राप्त करना।


 const person = { // data name: "Jane", age: 0, // behavior grow() { this.age += 1; } }; Object.getOwnPropertyNames(person); // [ 'name', 'age', 'grow' ]


यह कुंजियों को एक सारणी के रूप में लौटाता है, और हम निम्नलिखित उदाहरण में उन कुंजियों पर लूपिंग कर रहे हैं:


 for (const name of Object.getOwnPropertyNames(source)) {


निम्नलिखित जाँच यह है कि क्या गंतव्य और स्रोत में वही कुंजी है जिस पर हम वर्तमान में लूपिंग कर रहे हैं:


 if (!overwrite && Object.hasOwn(destination, name)) { // Skip descriptor continue; }


अगर ओवरराइट गलत है, तो उस प्रॉपर्टी को छोड़ दें; ओवरराइट न करें। continue यही करता है - यह लूप को अगले पुनरावृत्ति पर ले जाता है और नीचे दिए गए कोड को नहीं चलाता है, जो निम्न कोड है:


 // Copy descriptor const descriptor = Object.getOwnPropertyDescriptor(source, name); Object.defineProperty(destination, name, descriptor);


हम पहले से ही जानते हैं कि getOwnProperty क्या मतलब है। नया शब्द है descriptor । आइए इस फ़ंक्शन को अपने स्वयं के person ऑब्जेक्ट पर परीक्षण करें:


 const person = { // data name: "Jane", age: 0, // behavior grow() { this.age += 1; } }; Object.getOwnPropertyDescriptor(person, "grow"); // { // value: [Function: grow], // writable: true, // enumerable: true, // configurable: true // }


यह हमारे grow फ़ंक्शन को मान के रूप में लौटाता है, और अगली पंक्ति स्वतः स्पष्ट है:


 Object.defineProperty(destination, name, descriptor);


यह हमारे डिस्क्रिप्टर को सोर्स से लेकर डेस्टिनेशन में लिख रहा है। यह सोर्स के अपने गुणों को हमारे डेस्टिनेशन ऑब्जेक्ट में अपने गुणों के रूप में कॉपी कर रहा है।


आइये अपने person ऑब्जेक्ट में एक उदाहरण लेते हैं:


 const val = { value: function isAlien() { return false; }, enumerable: true, writable: true, configurable: true, }; Object.defineProperty(person, "isAlien", val);


अब person पास isAlien गुण परिभाषित होना चाहिए।


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


हमने इस स्रोत कोड स्तर में अपना पहला मॉड्यूल सफलतापूर्वक कवर कर लिया है, और आगे और भी रोमांचक चीजें आने वाली हैं।


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


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


सौभाग्य से, merge-descriptors उपयोग एक्सप्रेस में किया जाता है, जो हमारे शुरुआती स्रोत कोड अध्ययन के रूप में हमारा ध्यान केंद्रित है। इसलिए जब तक हमें नहीं लगता कि हमने एक्सप्रेस का पर्याप्त अच्छा उपयोग कर लिया है, तब तक और अधिक Express.js स्रोत कोड लेखों की अपेक्षा करें, फिर Node.js जैसे किसी अन्य मॉड्यूल या टूल पर स्विच करें।


इस बीच आप जो कर सकते हैं वह है मर्ज डिस्क्रिप्टर में टेस्ट फ़ाइल पर नेविगेट करना, पूरी फ़ाइल को पढ़ना। अपने आप स्रोत को पढ़ना महत्वपूर्ण है, कोशिश करें और पता लगाएं कि यह क्या करता है और परीक्षण कर रहा है फिर इसे तोड़ दें, हाँ और इसे फिर से ठीक करें या अधिक परीक्षण जोड़ें!


यदि आप अपने प्रोग्रामिंग कौशल को बढ़ाने के लिए अधिक विशिष्ट व्यावहारिक और लंबी सामग्री में रुचि रखते हैं, तो आप को-फाई पर अधिक जानकारी पा सकते हैं।