जावास्क्रिप्ट में वस्तुओं की स्वतंत्र गहरी क्लोनिंग

किसी भी प्रोग्रामिंग भाषा में, डेटा प्रकार होते हैं जो प्रोग्रामर आगे काम करने के लिए विषयों का वर्णन करते हैं और यदि आवश्यक हो, तो उन्हें संसाधित करते हैं। जावास्क्रिप्ट एक अपवाद नहीं है, इसमें आदिम ( Number , String , Boolean , Symbol , आदि) और संदर्भ ( Array , Object , Function , Maps , Sets , आदि) डेटा प्रकार हैं। यह ध्यान दिया जाना चाहिए कि आदिम डेटा प्रकार अपरिवर्तनीय हैं - उनके मूल्यों को संशोधित नहीं किया जा सकता है, लेकिन केवल एक नए पूर्ण मूल्य के साथ ओवरराइट किया जा सकता है, लेकिन संदर्भ डेटा प्रकारों के साथ विपरीत सच है। उदाहरण के लिए, प्रकार Number और Object चर घोषित करें:

 let num = 5; let obj = { a: 5 }; 

हम num चर को संशोधित नहीं कर सकते, हम केवल इसके मूल्य को फिर से लिख सकते हैं, लेकिन हम obj चर को संशोधित कर सकते हैं:

 let num = 10; let obj = { a: 5, b: 6 }; 

जैसा कि आप देख सकते हैं, पहले मामले में हमने चर के मूल्य को ओवरराइट किया, और दूसरे में हमने ऑब्जेक्ट का विस्तार किया। इससे हम यह निष्कर्ष निकालते हैं कि आदिम डेटा प्रकारों का विस्तार नहीं किया जा सकता है, और संदर्भ डेटा प्रकारों के साथ हम ऐसा कर सकते हैं, यहां तक ​​कि const संशोधक के साथ भी।

बाद को जमे हुए किया जा सकता है, उदाहरण के लिए, Object.freeze(obj) का उपयोग करके, लेकिन यह विषय लेख के दायरे से परे है (जिज्ञासु Object.defineProperty के लिए लिंक, ऑब्जेक्ट को परिवर्तनों से बचाता है )।

जावास्क्रिप्ट में फ़ंक्शन के लिए डेटा प्रकार कैसे पारित किए जाते हैं? प्रत्येक js प्रोग्रामर शायद इस प्रश्न का उत्तर आसानी से दे देगा, लेकिन फिर भी, मान लें: आदिम डेटा प्रकार हमेशा केवल मान से फ़ंक्शन में पास किए जाते हैं, और संदर्भित व्यक्ति हमेशा संदर्भ द्वारा ही होते हैं। और यहां उत्तरार्द्ध के साथ, कुछ स्थितियों में, समस्याएं पैदा होती हैं। आइए एक उदाहरण देखें:

 const arr = [0, 1, 2, 3, 4, 5]; console.log("Array: ", arr); // output: Array: [0, 1, 2, 3, 4, 5] 

इस मामले में, हमने केवल संख्याओं की एक सरणी घोषित की और इसे कंसोल में प्रदर्शित किया। अब हम इसे एक ऐसे फंक्शन में पास करते हैं जो एक नया एरे देता है, लेकिन दूसरे तर्क में कुछ वैल्यू को जोड़ने के साथ, नए एग्जाम के अंत तक:

 const arr = [0, 1, 2, 3, 4, 5]; console.log("Old array: ", arr); // "Old array: " [0, 1, 2, 3, 4, 5] const newArr = insertValToArr(arr, 15); console.log("New array: ", newArr); // output: "New array: " [0, 1, 2, 3, 4, 5, 15] console.log("Old array: ", arr); // output: "Old array: " [0, 1, 2, 3, 4, 5, 15] function insertValToArr(arr, val) { const newArr = arr; newArr.push(val); return newArr; } 

जैसा कि हम कंसोल निष्कर्ष से देख सकते हैं, न केवल नई सरणी बदल गई है, बल्कि पुरानी भी है। यह इसलिए हुआ क्योंकि insertValToArr फंक्शन में हमने सिर्फ एक एरे को दूसरे const newArr = arr , और इसलिए एक मौजूदा ऐरे का लिंक बनाया और जब हमने एक नई एरे को संशोधित करने की कोशिश की, तो उसने पुराने एरे के मेमोरी एरिया को संदर्भित किया और, मोटे तौर पर इसे बदल दिया। और चूँकि दोनों सरणियाँ एक ही मेमोरी क्षेत्र को संदर्भित करती हैं, इसलिए उनका मान समान होगा। आइए हमारे फ़ंक्शन को बदलें ताकि यह पुरानी सरणी को बदल न सके:

 const arr = [0, 1, 2, 3, 4, 5]; const newArr = insertValToArr(arr, 15); console.log("New array: ", newArr); // output: "New array: " [0, 1, 2, 3, 4, 5, 15] console.log("Old array: ", arr); // output: "Old array: " [0, 1, 2, 3, 4, 5] function insertValToArr(arr, val) { const newArr = []; arr.forEach((value, ind) => { newArr[ind] = value}); newArr.push(val); return newArr; } 

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

आइए जावास्क्रिप्ट को प्रदान करने वाली वस्तुओं की प्रतिलिपि बनाने के लिए मानक तरीकों को देखें - Object.assign () का उपयोग लक्ष्य वस्तु के लिए एक या एक से अधिक स्रोत वस्तुओं से अपने स्वयं के सभी गुणों की गणना करने के लिए किया जाता है। कॉपी करने के बाद, यह लक्ष्य वस्तु को वापस करता है। इस पर विचार करें:

 const obj = { a: 1 }; const newObj = Object.assign({}, obj); console.log(newObj); // output: { a: 1, b: 2 } console.log(obj); // output: { a: 1, b: 2 } 

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

चरण 1: ऑब्जेक्ट Z को घोषित और प्रारंभ करें, और क्लोनिंग से पहले और बाद की तुलना के लिए कंसोल आउटपुट भी बनाएं:

 const Z = { a: 5, b: { g: 8, y: 9, t: { q: 48 } }, x: 47, l: { f: 85, p: { u: 89, m: 7 }, s: 71 }, r: { h: 9, a: 'test', s: 'test2' } }; console.log('Z object before cloning: ', Z); 

छवि

चरण 2: सामान्य असाइनमेंट और डीप क्लोनिंग के बीच अंतर दिखाने के लिए ऑब्जेक्ट Z को refToZ ऑब्जेक्ट में असाइन करें:

 const refToZ = Z; 

चरण 3: डी को क्लिक करें ऑब्जेक्ट Z ऑब्जेक्ट Y को deepClone फ़ंक्शन का उपयोग करके और Y Z ऑब्जेक्ट के लिए एक नई संपत्ति जोड़ें Y उसके बाद, कंसोल में इन दो वस्तुओं को प्रदर्शित करें:

 const Y = deepClone(Z); function deepClone(obj) { const clObj = {}; for(const i in obj) { if (obj[i] instanceof Object) { clObj[i] = deepClone(obj[i]); continue; } clObj[i] = obj[i]; } return clObj; } Y.addnlProp = { fd: 45 }; console.log('Z object after cloning: ', Z); console.log('Y object: ', Y); 

छवि

छवि

कंसोल में, हम स्पष्ट रूप से देखते हैं कि Y ऑब्जेक्ट को बदलना, एक नई संपत्ति जोड़ना, हम Z ऑब्जेक्ट को नहीं बदलते हैं और बाद वाले के पास इसके शरीर में addnlProp संपत्ति नहीं होगी।

चरण 4: प्रॉपर्टी x बदलें, जो ऑब्जेक्ट Z और Y के शरीर में है Y और फिर से दोनों वस्तुओं को कंसोल में प्रदर्शित करें:

 Yx = 76; console.log('Y object: ', Y); console.log('Z object: ', Z); 

छवि

छवि

उसी गुण को ऑब्जेक्ट Y में बदलने से, हम शरीर Z में मौजूद संपत्ति को प्रभावित नहीं करते हैं Z

चरण 5: अंतिम चरण में, तुलना के लिए, हम बस addToZ संपत्ति को 100 मान के साथ refToZ ऑब्जेक्ट में refToZ और कंसोल में सभी तीन ऑब्जेक्ट प्रदर्शित करते हैं:

 refToZ.addToZ = 100; console.log('refToZ object: ', refToZ); console.log('Z object: ', Z); console.log('Y object: ', Y); 

छवि

छवि

छवि

refToZ ऑब्जेक्ट को बदलकर refToZ हमने Z भी बदल दिया, लेकिन Y प्रभावित नहीं हुआ। इससे हम यह निष्कर्ष निकालते हैं कि हमारा कार्य गुणों के साथ एक स्वतंत्र नई वस्तु बनाता है और एक मौजूदा वस्तु से उनके मूल्य ( deepClone फ़ंक्शन को लागू करने का कोड deepClone पर पाया जा सकता है)।

आइए हम इस फ़ंक्शन के कार्यान्वयन पर ध्यान दें। उत्तरार्द्ध वस्तु के किसी भी घोंसले का पता लगाता है, यह जानने के बिना भी। वह यह कैसे करती है? बात यह है कि इस मामले में हम ग्राफ़ - गहराई खोज के लिए प्रसिद्ध एल्गोरिथ्म का उपयोग करते हैं। एक ऑब्जेक्ट एक ग्राफ है जिसमें एक या कई शाखाएं होती हैं, जो बदले में उनकी शाखाएं हो सकती हैं, आदि। हमें सब कुछ खोजने के लिए, हमें प्रत्येक शाखा में जाने और उसकी गहराई में जाने की आवश्यकता है, इसलिए हम ग्राफ़ में प्रत्येक नोड को ढूंढेंगे और उसके मान प्राप्त करेंगे। गहरी खोज को 2 तरीकों से लागू किया जा सकता है: पुनरावृत्ति और एक लूप का उपयोग करना। दूसरा तेज हो सकता है, क्योंकि यह कॉल स्टैक को नहीं भरेगा, जो बदले में पुनरावृत्ति करता है। deepClone फ़ंक्शन के हमारे कार्यान्वयन में deepClone हमने लूप के साथ पुनरावृत्ति के संयोजन का उपयोग किया। यदि आप एल्गोरिदम के बारे में किताबें पढ़ना चाहते हैं, तो मैं आपको आदित्य भार्गव "ग्रोकेम एल्गोरिदम" या अधिक गहराई से थॉमस कॉर्मेन "एल्गोरिदम: निर्माण और विश्लेषण" शुरू करने की सलाह देता हूं।

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

Source: https://habr.com/ru/post/hi480786/


All Articles