सी # और जावास्क्रिप्ट की तुलना। मूल बातें

सी # और डच


प्रोग्रामिंग में मेरा कम या ज्यादा गंभीर रास्ता C # में प्रोग्राम लिखने के साथ शुरू हुआ, कभी-कभी मैंने जावास्क्रिप्ट में लिखने की कोशिश की, और अब और फिर उन स्थितियों में एक स्तूप में गिर गया जहां मैंने गलत तरीके से चर नाम दर्ज किया और बाद में इसके बारे में पता चला। कई साल डिबगिंग का एक घंटा, चूंकि मैं अपने कंपाइलर के पास नहीं था, जिससे मुझे मुश्किल समय में मदद मिलेगी। कुछ समय बाद, सी # के अलावा, मैंने बहुत सारे जावास्क्रिप्ट कोड लिखना शुरू कर दिया और अब मैं इसे बिना किसी परेशानी के कर सकता हूं, मैं अब निहित प्रकार की कास्टिंग और गतिशील टाइपिंग से भ्रमित नहीं हूं।


इस लेख में, मैं इन भाषाओं के अपने मूल ज्ञान को व्यवस्थित करना और उनकी समानता और अंतर पर विचार करना चाहूंगा। यह लेख C # डेवलपर्स के लिए एक मार्गदर्शक के रूप में काम कर सकता है जो जावास्क्रिप्ट और इसके विपरीत सीखना चाहते हैं। मैं यह भी नोट करना चाहता हूं कि यह लेख क्लाइंट-साइड JS की क्षमताओं का वर्णन करता है, क्योंकि मेरे पास Node.js. पर कोई विकास अनुभव नहीं है। इसलिए, यदि आपने अभी भी ब्याज नहीं खोया है, तो आइए शुरू करें।


नेमस्पेस और जेएस मॉड्यूल


प्रत्येक कार्यक्रम में, चर, कार्यों, वर्गों या अन्य वस्तुओं के नामों में संघर्ष से बचने के लिए, हम उन्हें कुछ क्षेत्रों में जोड़ते हैं। इस प्रकार, यदि दो अलग-अलग क्षेत्रों में एक ही नाम के तत्व होते हैं, तो कोई संघर्ष नहीं होगा।


C # में, किसी प्रोग्राम को भागों में विभाजित करने के लिए नेमस्पेस का उपयोग किया जाता है। उन्हें घोषित करने के लिए कीवर्ड namespace उपयोग किया जाता है। उदाहरण के लिए, यदि हम उपयोगकर्ता इंटरफ़ेस घटकों का एक सेट बनाना चाहते हैं, तो उन सभी को एक नामस्थान में रखना तर्कसंगत है, उदाहरण के लिए, Components । यह प्रथागत है कि नामस्थान में निम्नलिखित नामकरण [AssemblyName].[DirectoryName].[DirectoryName].[...] नेम [AssemblyName].[DirectoryName].[DirectoryName].[...] । प्रत्येक फ़ाइल में उपयोगकर्ता इंटरफ़ेस घटक के वर्ग को नामस्थान के अंदर रखा जाना चाहिए:


ComboBox.cs फ़ाइल की सामग्री:


 namespace AssemblyName.Components { public class ComboBox { // ... } } 

घटकों का उपयोग शुरू करने के लिए, आपको असेंबलीनाम using AssemblyName.Components उन्हें नामस्थान से आयात करने की आवश्यकता है। इस एक-लाइन कनेक्शन विधि के साथ, हम सभी वस्तुओं को वर्तमान फ़ाइल में आयात करते हैं।


जेएस एक ही उद्देश्य के लिए ईएस मॉड्यूल का उपयोग करता है। उनका उपयोग करते समय, हम कुछ हद तक अतिरिक्त कोड लिखकर नामस्थान के व्यवहार का अनुकरण करते हैं। एक घटक पुस्तकालय के साथ एक ही उदाहरण पर विचार करें। मान लें कि हमारे पास Components फोल्डर है, जिसमें यूजर इंटरफेस ComboBox.js , Button.js , Button.js , आदि के Button.jsComponents फ़ोल्डर में नाम स्थान की तुलना में समान व्यवहार प्राप्त करने के लिए, आपको एक index.js फ़ाइल बनानी होगी जिसमें निम्नलिखित कोड होंगे:


 export { default as Dialog } from './ComboBox'; export { default as Button } from './Button'; export { default as Checkbox } from './Checkbox'; // ... 

इन घटकों का उपयोग करने के लिए, आपको उन्हें वर्तमान फ़ाइल में आयात करना होगा। यह निम्नानुसार किया जा सकता है: import * as Components from './../Components' , कीवर्ड से, हमें उस फ़ोल्डर में पथ निर्दिष्ट करने की आवश्यकता है जिसमें सभी वर्णित घटक स्थित हैं।


चर घोषित करने के तरीके


var कीवर्ड


जैसा कि आप जानते हैं, सी # एक दृढ़ता से टाइप की गई प्रोग्रामिंग भाषा है, इसलिए, जब एक चर घोषित किया जाता है, तो कंपाइलर को इसका प्रकार पता होना चाहिए, इसके लिए आमतौर पर इसके नाम से पहले संकेत दिया जाता है।


 double pi = 3.14; User user = new User(); int[] a = new[] { 0, 1, 2 }; 

लेकिन हम संकलक को यह भी बता सकते हैं कि उसे असाइनमेंट साइन के बाद अभिव्यक्ति से अपने प्रकार का अनुमान लगाना चाहिए। यह C # 3.0 में var कीवर्ड की शुरुआत करके संभव हुआ।


 // i - int var i = 5; // a - int[] var a = new[] { 0, 1, 2 }; 

var साथ var हम गुमनाम प्रकार की वस्तुएँ बना सकते हैं:


 // anon -      var anon = new { Name = "Terry", Age = 34 }; var type = anon.GetType();//"<>f__AnonymousType0`2" 

जावास्क्रिप्ट में, आप वेरिएबल घोषित करने के लिए वेरिएबल कीवर्ड का भी उपयोग कर सकते हैं, हालाँकि, C # के विपरीत, इन वेरिएबल्स का दायरा पूरे फंक्शन या window ऑब्जेक्ट का होगा, अगर वेरिएबल को फंक्शन के बाहर घोषित किया गया था।


 var a = 5 //   - window function go() { var a = 6 //   -  go // ... } 

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


स्थिरांक


C # और JavaScript दोनों एक स्थिर क्षेत्र घोषित करने के लिए const कीवर्ड का उपयोग करते हैं। सच है, यह ध्यान देने योग्य है कि इस मामले में एक निरंतर की अवधारणा इन भाषाओं के लिए अलग है।


सी # में, एक स्थिरांक एक अभिव्यक्ति है जिसका संकलन चरण में पूरी तरह से मूल्यांकन किया जा सकता है, अर्थात। स्थिरांक संख्या, बूलियन, स्ट्रिंग्स या अशक्त संदर्भ हो सकते हैं।


 const int c1 = 5; const int c2 = c1 + 100; const string c3 = ""; const bool c4 = true; const User human = null; const User human = new User(firstName); //,   

जावास्क्रिप्ट में, एक स्थिर का मान भी नहीं बदला जा सकता है, हालांकि, C # के रूप में मूल्य पर कोई प्रतिबंध नहीं है, आप इसके लिए कोई मान / ऑब्जेक्ट / सरणियाँ असाइन कर सकते हैं। हालाँकि, यदि किसी वस्तु को स्थिरांक को सौंपा जाता है, तो स्थिरांक स्वयं परिवर्तनों से सुरक्षित रहता है, लेकिन इसके अंदर के गुण नहीं:


 const c1 = 5; const c2 = c1 + 100; const c3 = ""; const c4 = true; const user = { name: "" }; user.name = ""; //  user = 5; // ,   

void कीवर्ड


इस लेख को लिखते समय, मैंने कंसोल में कार्यों का प्रयोग किया और आदत से बाहर निकलकर फ़ंक्शन को C # void SomeFunction... रूप में वर्णन करना शुरू किया और यह मेरे लिए एक बड़ा आश्चर्य था जब मुझे पता चला कि जावास्क्रिप्ट कीवर्ड void । जैसा कि यह पता चला है, जावास्क्रिप्ट में void एक अपरिपक्व ऑपरेटर है जो एक ऑपरेंड के मूल्य की गणना करता है, फिर इसे त्याग देता है और undefined वापस लौटता है।


 alert("!"); // "!" alert(void "!"); // undefined 

इस प्रकार, हम कह सकते हैं कि void का उपयोग स्पष्ट रूप से रिटर्न वैल्यू की अनुपस्थिति को इंगित करता है, इसके उपयोग के उदाहरणों के बारे में अधिक जानकारी के लिए, अगला लेख देखें


सी # में, void एक ऑपरेटर नहीं है, लेकिन अनिवार्य रूप से एक समान अर्थ है। यहां, यह फ़ंक्शन रिटर्न मान की अनुपस्थिति को इंगित करता है:


 public void SampleMethod() { // ... } 

हालांकि, जैसा कि आप ऊपर दिए गए उदाहरण में देख सकते हैं, void उस जगह पर है जहां रिटर्न वैल्यू का प्रकार आमतौर पर इंगित किया गया है, और यह कोई दुर्घटना नहीं है, क्योंकि सी # में void भी एक प्रकार है।


 var t = typeof(void); t.Name // System.Void 

एक प्रकार के रूप में void केवल संकेत के साथ काम करते समय असुरक्षित संदर्भ में उपयोग किया जा सकता है।


  unsafe { void* identifier; //,    } 

कीवर्ड new


जावास्क्रिप्ट में, new कीवर्ड एक ऑपरेटर है, और इसका उपयोग कई सी-लाइक भाषाओं के लिए एक वस्तु बनाने के लिए सामान्य तरीके से किया जाता है।


 function Animal() { //... } const animal = new Animal(); 

C # में, new का उपयोग निम्नलिखित उद्देश्यों के लिए किया जा सकता है:


  • वस्तुओं को बनाने के लिए;
  • बेस क्लास के विरासत वाले सदस्य को छिपाने के लिए;
  • उन प्रकारों को सीमित करने के लिए जिनका उपयोग जेनेरिक क्लास में टाइप पैरामीटर के लिए तर्कों के रूप में किया जा सकता है।

पहला मामला जावास्क्रिप्ट में new प्रयोग के समान है।


 class Animal { //... } var animal = new Animal(); 

बुनियादी डेटा प्रकार


प्रत्येक भाषा में डेटा प्रकार होते हैं - आदिम, जिसके आधार पर अन्य डेटा प्रकार बनाए जाते हैं, आइए C # और जावास्क्रिप्ट में हमें प्रदान किए गए डेटा प्रकारों को देखें।


आदिम सी # प्रकार:


  • sbyte पूर्णांक: sbyte , short , int , long
  • ushort पूर्णांक: byte , ushort , ulong , ulong
  • यूनिकोड वर्ण: char
  • यूनिकोड वर्ण सेट: char
  • फ्लोटिंग पॉइंट नंबर: float , double
  • प्रीसीमल दशमलव: decimal
  • बूलियन मूल्य: bool

आधार वर्ग Object


जेएस के लिए:


आदिम डेटा प्रकार:


  • संख्या number
  • स्ट्रिंग string
  • बूलियन boolean
  • विशेष null
  • विशेष अर्थ undefined
  • symbol

आधार प्रकार Object


दोनों भाषाओं की प्रधानता का अध्ययन करने के बाद, हम निम्नलिखित निष्कर्ष पर आ सकते हैं:


  • संख्या प्रकारों के पर्याप्त बड़े सेट के बजाय, जावास्क्रिप्ट में एक ही प्रकार की number ;
  • जावास्क्रिप्ट में एक char प्रकार नहीं है, इसके बजाय, एक string प्रकार का उपयोग करें;
  • दोनों भाषाओं में, आधार प्रकार Object ;
  • JS की एक विशिष्ट विशेषता यह है कि null और undefined को अलग-अलग प्रकारों में विभाजित किया जाता है, जबकि C # null में एक कीवर्ड होता है जो किसी मान के अभाव का संकेत देता है।
  • जेएस का symbol प्रकार है, जो मुख्य रूप से जावास्क्रिप्ट मानक के अंदर ही उपयोग किया जाता है, ताकि मौजूदा कोड आधार के साथ संघर्ष के बिना नई कार्यक्षमता जोड़ने में सक्षम हो।

एक नियम के रूप में, अब अधिक से अधिक एप्लिकेशन हैं जिसमें क्लाइंट पर डेटा को संसाधित करना आवश्यक है, जिसकी गणना में अधिक सटीकता की आवश्यकता होती है। वर्तमान में जावास्क्रिप्ट में बड़ी संख्या के साथ काम करने की अंतर्निहित क्षमता का अभाव है, लेकिन निकट भविष्य में इसमें नए प्रकार के BigInt को जोड़ने की योजना है। C # में समान समस्याओं को हल करने के लिए एक वर्ग System.Numerics.BigInteger


वस्तु प्रकार की जाँच


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


typeof ऑपरेटर


टाइप जानकारी के लिए, C # और JavaScript दोनों में typeof ऑपरेटर है। आइए देखें कि यह दोनों भाषाओं में कैसे काम करता है:


C # में, typeof ऑपरेटर को एक प्रकार पर लागू किया जाता है और Type वर्ग की एक वस्तु देता है जिसमें सभी प्रकार की जानकारी होती है।


 namespace Zoo { public class Animal {} } Type t = typeof(Animal); t.Name // 'Animal' t.FullName // 'Zoo.Animall' t.GetMethods //    t.GetFields //     // ... 

जेएस में, typeof एक स्ट्रिंग देता है जो ऑपरेंड के प्रकार का संकेत देता है।


 typeof 30 // 'number' typeof Symbol() // 'symbol' typeof undefined // 'undefined' //  typeof new Animal() // object typeof null // 'object' typeof [1,2,3] // 'object' //  typeof function() {} // 'function'; typeof class C {} // 'function'; 

ऊपर दिए गए उदाहरण में, आप इस ऑपरेटर की कुछ विशेषताओं को नोटिस कर सकते हैं। यह तर्कसंगत लगता है अगर अभिव्यक्ति typeof new Animal() स्ट्रिंग 'Animal' typeof [1,2,3] , और typeof [1,2,3] - स्ट्रिंग Array , हालांकि विरोधाभासी रूप से, दोनों मामलों में परिणाम 'object' । इसके अलावा, इस तथ्य के कारण कि जेएस में कक्षाएं फ़ंक्शन पर एक आवरण हैं, अभिव्यक्ति typeof class C {} 'class' बजाय 'function' लौटाएगी। एक और दिलचस्प तथ्य यह है कि typeof null अभिव्यक्ति 'object' लौटाएगा। जावास्क्रिप्ट में, इस ऑपरेटर में एक बड़ी खामी है: इसके लिए सभी गैर-आदिम वस्तुएं समान दिखती हैं, वे सभी एक ही object प्रकार हैं।


यह ध्यान देने योग्य है कि जावास्क्रिप्ट typeof में कुछ भी लागू किया जा सकता है: ऑब्जेक्ट, फ़ंक्शंस, कक्षाएं, आदि ... सी # में, यह ऑपरेटर केवल प्रकारों पर लागू होता है।


और उदाहरण है


एक प्रकार के बारे में जानकारी प्राप्त करने के अलावा, यह कभी-कभी यह सत्यापित करने के लिए उपयोगी हो सकता है कि कोई वस्तु किसी विशेष प्रकार की है।


C # में इन उद्देश्यों के लिए एक संचालक है।


 class Person { } // Programmer  Person class Programmer : Person { } var person = new Person(); var programmer = new Programmer(); person is Person //true person is Programmer //false programmer is Person //true programmer is Programmer //true 

जावास्क्रिप्ट में, यह पता लगाने के लिए कि ऑब्जेक्ट किस प्रकार का है, आपको ऑपरेटर - instanceof का उपयोग करने की आवश्यकता है।


 function Person() {} function Programmer() {} // Programmer  Person Programmer.prototype = Object.create(Person.prototype); var person = new Person(); var programmer = new Programmer(); console.log(person instanceof Person); // true console.log(person instanceof Programmer); // false console.log(programmer instanceof Person); // true console.log(programmer instanceof Programmer); // true 

बूलियन और अशक्त जाँच


लगभग हर जगह, एक Null reference exception प्राप्त नहीं करने के लिए, एक चर का उपयोग करने से पहले, हम इसे null लिए null , और जावास्क्रिप्ट के मामले में भी undefined


C # में, हम लगातार समान कोड देखते हैं:


 if(user != null && String.IsNullOrEmpty(user.name)) { user.SetName(""); } 

जावास्क्रिप्ट में, यह निर्माण कुछ छोटा लिखा जा सकता है। यह इस तथ्य के कारण है कि, जावास्क्रिप्ट में सी # के विपरीत, बहुत सारे मूल्यों को छोड़कर जब false को भी false माना जाता false :


  1. null
  2. undefined
  3. "" (खाली रेखा)
  4. 0
  5. NaN (संख्या नहीं)

इस प्रकार, उपरोक्त C # कोड निम्नानुसार लिखे जा सकते हैं:


 if (user && !user.name) { user.setName(""); } 

या


 user && !user.name && user.setName(""); 

इस तथ्य के कारण कि null जांच सर्वव्यापी हैं, N 6.0 में संचालक प्रसार संचालक जोड़ा गया था .?


C # कोड:


 if (user != null && user.parent != null && user.parent.parent != null) { user.parent.parent.SetName(""); } 

इसकी मदद से, इस कोड अनुभाग को इस प्रकार फिर से लिखा जा सकता है:


 user?.parent?.parent?.SetName(""); 

जावास्क्रिप्ट में, आमतौर पर निम्नानुसार किया जाता है:


 user && user.parent && user.parent.parent && user.parent.parent.setName(""); 

डिफ़ॉल्ट मान सेट करना


डिफ़ॉल्ट मान सेट करने के लिए एक और सामान्य ऑपरेशन है, C # Null Coalescing Operator में संस्करण 2.0 से - दिखाई दिया ??


C # कोड की निम्नलिखित दो पंक्तियाँ समतुल्य हैं:


 var name = user != null && user.name != null ? user.name : ""; var name = user?.name ?? ""; 

जावास्क्रिप्ट में, एक समान ऑपरेशन आमतौर पर निम्नानुसार किया जाता है।


 var name = user && user.name || ""; 

हालाँकि, हम ऑपरेटर्स && और || केवल अगर 0 , false और खाली स्ट्रिंग मान्य मान नहीं हैं।


निकट भविष्य में, ऑपरेटरों ?. , ?? जावास्क्रिप्ट में दिखाई देना चाहिए (वे अब स्टेज 0 चरण पार कर चुके हैं), जावास्क्रिप्ट में इन ऑपरेटरों के बारे में अधिक विवरण लेख में पाया जा सकता है।


यह कीवर्ड


C # और JavaScript दोनों में this । आमतौर पर C # को समझने का उद्देश्य सीधा है, लेकिन जावास्क्रिप्ट में यह सबसे जटिल भाषा अवधारणाओं में से एक है। आगे हम इसके उदाहरण पर आवेदन पर विचार करेंगे।


C # में, this कक्षा के वर्तमान उदाहरण की ओर इशारा करता है।


 class User { public string Name { get; set; } public void PrintEmployee() { Console.WriteLine(this.name); } } var employee = new Employee(); E1.PrintEmployee(); 

इस उदाहरण में, Console.WriteLine(this.name) अभिव्यक्ति में, this employee चर को इंगित करता है।


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


जावास्क्रिप्ट में, this कॉल का संदर्भ कहा जाता है और फ़ंक्शन को कॉल करने पर निर्धारित किया जाएगा। यदि आप अलग-अलग वस्तुओं के संदर्भ में एक ही फ़ंक्शन चलाते हैं, तो यह एक अलग प्राप्त करेगा:


 var user = { firstName: "" }; var admin = { firstName: "" }; function func() { alert( this.firstName ); } user.f = func; admin.g = func; // this    : user.f(); //  admin.g(); //  func();// undefined -    this -   window 

इसके अलावा, जावास्क्रिप्ट में स्पष्ट रूप से this फ़ंक्शन के उपयोग के मूल्य को स्पष्ट रूप से निर्दिष्ट करने की संभावना है: call , bind , apply । उदाहरण के लिए, ऊपर दिए गए उदाहरण को इस प्रकार लिखा जा सकता है:


 var user = { firstName: "" }; var admin = { firstName: "" }; function func() { alert( this.firstName ); } // this    : func.call(user); //  func.call(admin); //  func.bind(user)();//  func.bind(admin)();//  

destructurization


स्थानीय चर के लिए किसी वस्तु के कई क्षेत्रों को निर्दिष्ट करना अक्सर आवश्यक होता है। उदाहरण के लिए, आप समान कोड का कितनी बार निरीक्षण करते हैं?


 void Method(User user) { var firstName = user.FirstName; var lastName = user.LastName; //... } 

ऐसे उद्देश्यों के लिए, आप विनाशकारी उपयोग कर सकते हैं। दोनों भाषाएँ अलग-अलग डिग्री के लिए इस सुविधा का समर्थन करती हैं।


सी # 7.0 ने विनाशकारी का समर्थन करने के लिए एक नए प्रकार के फ़ंक्शन को डिकंस्ट्रक्टर्स कहा। डिकंस्ट्रक्टर घोषित करने के लिए, हमें Deconstruct नामक एक विधि को परिभाषित करने की आवश्यकता है, जिसके सभी मापदंडों को out संशोधक के साथ घोषित किया जाना चाहिए:


 class Person { public string FirstName { get; set; } public string LastName { get; set; } //   public void Deconstruct(out string firstName, out string lastName) { firstName = this.FirstName; lastName = this.LastName; } } ... Person person = new Person { FirstName = "", LastName = "" }; (string firstName, string lastName) = person; (string firstName, _ ) = person; 

जावास्क्रिप्ट में विनाश या (विनाशकारी असाइनमेंट) के लिए समर्थन छठे एक्मास्क्रिप्ट मानक में दिखाई दिया। उसकी मदद से। आप एक सरणी या ऑब्जेक्ट को एक साथ कई वेरिएबल्स में असाइन कर सकते हैं, इसे भागों में तोड़ सकते हैं।


 let [firstName, lastName] = ["", ""]; let [firstName, _ ] = ["", ""]; let { firstName, lastName } = { firstName: "", lastName: "" }; let { firstName } = { firstName: "", lastName: "" }; 

यह ध्यान देने योग्य है कि जावास्क्रिप्ट में पुनर्गठन में सी # की तुलना में अधिक विशेषताएं हैं:


  • चर का क्रम बदलें;
  • डेकोस्ट्रक्टर्स को स्पष्ट रूप से घोषित करने की आवश्यकता नहीं है;
  • ऐरे विनाशकारी समर्थन;
  • डिफ़ॉल्ट मान सेट करना;
  • एक भिन्न नाम के साथ एक वस्तु के गुणों को असाइन करना;
  • नेस्ट विनाशकारी के लिए समर्थन।

निष्कर्ष


इस लेख में, हमने C # और जावास्क्रिप्ट भाषाओं की केवल सबसे बुनियादी अवधारणाओं पर चर्चा की है। लेकिन कई पहलू अप्रभावित रहे:


  • संग्रह
  • कार्यों
  • कक्षाएं
  • बहु सूत्रण

इनमें से प्रत्येक विषय काफी व्यापक है और बाद में एक अलग लेख में इसका खुलासा किया जाएगा।

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


All Articles