
بدأت مسيرتي الأكثر أو الأقل خطورة في البرمجة بكتابة برامج في C # ، وأحيانًا حاولت الكتابة في جافا سكريبت ، ثم وقعت الآن في ذهول في المواقف التي أدخلت فيها اسم المتغير بشكل غير صحيح واكتشفته لاحقًا سنوات عديدة ساعة من التصحيح ، لأنني لم أكن بالقرب من المترجم ، الأمر الذي سيساعدني في الخروج في الأوقات الصعبة. بعد مرور بعض الوقت ، بالإضافة إلى C # ، بدأت في كتابة الكثير من تعليمات JavaScript البرمجية ، ويمكنني الآن القيام بذلك دون أي صعوبات ، لم أعد أشعر بالارتباك بسبب نوع الكتابة الضمني والكتابة الديناميكية.
في هذه المقالة ، أرغب في تنظيم معرفتي الأساسية بهذه اللغات والنظر في أوجه التشابه والاختلاف بينها. يمكن أن تكون هذه المقالة بمثابة دليل لمطوري C # الذين يرغبون في تعلم JavaScript والعكس صحيح. أريد أيضًا أن أشير إلى أن هذه المقالة تصف إمكانات JS من جانب العميل ، حيث لا أملك خبرة تطوير على Node.js. لذا ، إذا كنت لا تزال لم تفقد الاهتمام ، فلنبدأ.
وحدات مساحة الاسم وشبيبة
في كل برنامج ، من أجل تجنب التضارب في أسماء المتغيرات أو الوظائف أو الفئات أو الكائنات الأخرى ، نقوم بدمجها في بعض المناطق. وبالتالي ، إذا احتوت منطقتان مختلفتان على عناصر تحمل نفس الاسم ، فلن يحدث تعارض.
في C # ، يتم استخدام مساحات الأسماء لتقسيم البرنامج إلى أجزاء. namespace استخدام namespace الكلمات الرئيسية للإعلان عنها. على سبيل المثال ، إذا أردنا إنشاء مجموعة من مكونات واجهة المستخدم ، فمن المنطقي أن نضعها كلها في مساحة اسم واحدة ، على سبيل المثال ، Components . من المعتاد أن تحتوي مساحة الاسم على التسمية التالية [AssemblyName].[DirectoryName].[DirectoryName].[...] . في كل ملف ، يجب وضع فئة مكون واجهة المستخدم داخل مساحة الاسم:
محتويات ملف ComboBox.cs :
 namespace AssemblyName.Components { public class ComboBox {  
لبدء استخدام المكونات ، تحتاج إلى استيرادها من مساحة الاسم كما يلي using AssemblyName.Components . باستخدام طريقة الاتصال ذات الخط الواحد هذه ، نستورد جميع الكائنات في الملف الحالي.
يستخدم JS وحدات ES لنفس الغرض. عند استخدامها ، نقوم إلى حد ما بمحاكاة سلوك مساحات الأسماء من خلال كتابة كود إضافي. خذ بعين الاعتبار المثال نفسه مع مكتبة مكون. لنفترض أن لدينا مجلد Components ، الذي يحتوي على مكونات واجهة المستخدم ComboBox.js و Button.js و Button.js وما إلى ذلك. من أجل الحصول على سلوك مماثل مقارنة بمساحة الاسم في مجلد Components ، تحتاج إلى إنشاء ملف 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
كما تعلمون ، C # هي لغة برمجة مكتوبة بقوة ، لذلك ، عند تعريف متغير ، يجب أن يعرف المترجم نوعه ، لذلك يشار إليه عادة قبل اسمه.
 double pi = 3.14; User user = new User(); int[] a = new[] { 0, 1, 2 }; 
ولكن يمكننا أيضًا أن نخبر المترجم أنه يجب أن يستنتج النوع بمفرده من التعبير بعد علامة التعيين. أصبح هذا ممكنًا من خلال تقديم الكلمة الأساسية var في C # 3.0.
 
باستخدام var يمكننا إنشاء كائنات من نوع مجهول:
 
في JavaScript ، يمكنك أيضًا استخدام الكلمة الأساسية var للإعلان عن المتغيرات ، ومع ذلك ، على عكس C # ، سيكون نطاق هذه المتغيرات هو الوظيفة أو كائن window بالكامل إذا تم الإعلان عن المتغير خارج الوظيفة.
 var a = 5 //   - window function go() { var a = 6 //   -  go // ... } 
على الرغم من أن لديك القدرة على إعلان المتغيرات باستخدام var في JavaScript ، لا يُنصح بذلك الآن ، بعد إصدار معيار ES6 ، تمت إضافة الكلمة الرئيسية let ، والتي تسمح لك أيضًا بالإعلان عن المتغيرات ، ولكن ميزتها هي أن نطاقها سيكون الكتلة التي يتم فيها الإعلان عنها ، وليس الوظيفة بأكملها.
الثوابت
يستخدم كل من C # و JavaScript الكلمة الأساسية const حقل ثابت. صحيح ، تجدر الإشارة إلى أن مفهوم الثابت في هذه الحالة يختلف عن هذه اللغات.
في C # ، الثابت هو تعبير يمكن تقييمه بالكامل في مرحلة التجميع ، أي يمكن أن تكون الثوابت أرقامًا أو منطقية أو سلاسل أو مراجع فارغة.
 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);  
في JavaScript ، لا يمكن أيضًا تغيير قيمة الثابت ، ومع ذلك ، لا توجد قيود على القيمة كما في C # ، يمكنك تعيين أي قيم / كائنات / صفائف لها. ومع ذلك ، إذا تم تعيين كائن لثابت ، فإن الثابت نفسه محمي من التغييرات ، ولكن ليس الخصائص الموجودة بداخله:
 const c1 = 5; const c2 = c1 + 100; const c3 = ""; const c4 = true; const user = { name: "" }; user.name = "";  
كلمة رئيسية void
أثناء كتابة هذا المقال ، جربت وظائف في وحدة التحكم وبدأت عادة وصف الوظيفة كما في C # void SomeFunction... وكانت مفاجأة كبيرة لي عندما اكتشفت أن كلمة JavaScript الأساسية void . كما اتضح ، فإن void في JavaScript هو عامل أحادي يحسب قيمة المعامل ، ثم يتجاهله ويعود undefined .
 alert("!"); // "!" alert(void "!"); // undefined 
وبالتالي ، يمكننا القول أن استخدام void يشير بوضوح إلى عدم وجود قيمة إرجاع ؛ لمزيد من التفاصيل حول أمثلة على استخدامه ، راجع المقالة التالية.
في C # ، لا void عامل تشغيل ، ولكن له بالضرورة معنى مشابه. هنا ، يشير إلى عدم وجود قيمة إرجاع دالة:
 public void SampleMethod() {  
ومع ذلك ، كما ترى في المثال أعلاه ، void في المكان الذي يُشار إليه عادةً نوع القيمة المرتجعة ، وهذا ليس مصادفة ، لأنه في C # void أيضًا نوع.
 var t = typeof(void); t.Name  
لا يمكن استخدام void كنوع إلا في سياق غير آمن عند العمل مع المؤشرات.
  unsafe { void* identifier;  
كلمة رئيسية new
في JavaScript ، تكون الكلمة الرئيسية new عامل تشغيل ، ويتم استخدامها بالطريقة المعتادة للعديد من اللغات المشابهة لـ C لإنشاء كائن.
 function Animal() { //... } const animal = new Animal(); 
في C # ، يمكن استخدام new للأغراض التالية:
- لإنشاء كائنات ؛
- لإخفاء العضو الموروث من الطبقة الأساسية ؛
- لتحديد الأنواع التي يمكن استخدامها كوسيطة لمعلمة نوع في فئة عامة.
الحالة الأولى مشابهة لاستخدام new في JavaScript.
 class Animal {  
أنواع البيانات الأساسية
تحتوي كل لغة على أنواع بيانات - بدائية تستند إليها أنواع البيانات الأخرى ، فلنلق نظرة على أنواع البيانات المقدمة لنا في C # وجافا سكريبت.
أنواع بدائية C #:
- عدد صحيح sbyte:sbyte،short،int،long
- عدد صحيح ushort:byte،ushort،uint،ulong
- أحرف Unicode: char
- مجموعة أحرف Unicode: char
- أرقام النقطة العائمة: float،double
- العشري decimal:decimal
- القيمة المنطقية: منطقية
الفئة الأساسية هي Object .
بالنسبة لشبيبة:
أنواع البيانات البدائية:
- رقم number
- سلسلة string
- منطقية boolean
- nullخاصة
- معنى خاص undefined
- symbol
النوع الأساسي هو Object .
بعد دراسة أساسيات كلتا اللغتين ، يمكن أن نصل إلى الاستنتاجات التالية:
- بدلاً من مجموعة كبيرة بما فيه الكفاية من أنواع الأرقام ، تحتوي JavaScript على numberنوع واحد ؛
- لا تحتوي JavaScript على نوع char؛ بدلاً من ذلك ، استخدم نوعstring؛
- في اللغتين ، النوع الأساسي هو Object؛
- السمة المميزة لـ JS هي أنه يتم فصل القيم nullوغيرundefinedإلى أنواع منفصلة ، بينما في C #nullهي كلمة رئيسية تشير إلى عدم وجود قيمة.
- يحتوي JS على نوع symbol، والذي يتم استخدامه بشكل أساسي داخل معيار JavaScript نفسه ، من أجل أن تكون قادرًا على إضافة وظائف جديدة دون تعارض مع قاعدة التعليمات البرمجية الحالية.
كقاعدة ، هناك الآن المزيد والمزيد من التطبيقات التي من الضروري فيها معالجة البيانات على العميل ، الأمر الذي يتطلب دقة أكبر في الحسابات. تفتقر جافا سكريبت حاليًا إلى القدرة المدمجة على العمل مع أعداد كبيرة ، ولكن في المستقبل القريب من المقرر إضافة نوع جديد من BigInt . لحل مشاكل مماثلة في C # هناك فئة System.Numerics.BigInteger .
فحص نوع الكائن
تدقيق النوع هو عملية نموذجية إلى حد ما لمعظم لغات البرمجة. بناءً على النوع ، يمكننا تنفيذ إجراءات مختلفة. على سبيل المثال ، ضع في اعتبارك مثالًا على الحياة: تسمع جرس الباب ، إذا جاء إليك جار مخمور (كائن من نوع الجار في حالة سكر ) لاقتراض المال ، فمن غير المحتمل أن تفتح له الباب ، ولكن إذا كان أفضل صديق لك خلف الباب (كائن من أفضل النوع صديق ) ، فأنت لا تتردد في السماح له بدخول الشقة. يوفر C # وجافا سكريبت أيضًا تسهيلات للتحقق من نوع الكائنات.
عامل typeof
للحصول على معلومات النوع ، يكون لكل من C # و JavaScript عامل typeof . دعونا نلقي نظرة على كيفية عملها باللغتين:
في C # ، يتم تطبيق عامل typeof على نوع وإرجاع كائن من فئة Type الذي يحتوي على كافة معلومات النوع.
 namespace Zoo { public class Animal {} } Type t = typeof(Animal); t.Name  
في JS ، تُرجع 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] - سلسلة Array ، مهما كانت متناقضة ، فإن النتيجة في كلتا الحالتين هي 'object' . أيضًا ، نظرًا لحقيقة أن الفئات في JS هي التفاف فوق الدالات ، فإن تعبير typeof class C {} سيُرجع 'function' بدلاً من 'class' . حقيقة أخرى مثيرة للاهتمام هي أن نوع التعبير typeof null سيُرجع 'object' . في JavaScript ، هذا العامل له عيب كبير: جميع الكائنات غير البدائية تبدو متشابهة ، وكلها لها نفس نوع object .
من الجدير بالذكر أنه في JavaScript typeof يمكن تطبيقه على أي شيء: الكائنات والوظائف والفئات وما إلى ذلك ... في C # ، ينطبق هذا العامل فقط على الأنواع.
بالإضافة إلى الحصول على معلومات حول نوع ما ، قد يكون من المفيد في بعض الأحيان التحقق من أن الكائن ينتمي إلى نوع معين.
في C # يوجد عامل تشغيل لهذه الأغراض.
 class Person { }  
في JavaScript ، من أجل معرفة نوع الكائن الذي تنتمي إليه ، تحتاج إلى استخدام عامل التشغيل - 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 ، وفي حالة جافا سكريبت ، أيضًا لغير undefined .
في C # ، نرى باستمرار كود مشابه:
 if(user != null && String.IsNullOrEmpty(user.name)) { user.SetName(""); } 
في JavaScript ، يمكن كتابة هذا البناء أقصر إلى حد ما. ويرجع ذلك إلى حقيقة أنه ، على عكس C # ، في JavaScript ، فإن العديد من القيم باستثناء false عند الإرسال تعتبر أيضًا false :
- null
- undefined
- "" (سطر فارغ)
- 0
- NaN(ليس رقمًا)
وبالتالي ، يمكن كتابة رمز C # أعلاه على النحو التالي:
 if (user && !user.name) { user.setName(""); } 
أو
 user && !user.name && user.setName(""); 
نظرًا لحقيقة أن عمليات التحقق null موجودة في كل مكان ، تمت إضافة عامل التشغيل Null Propagation في C # 6.0 .? .
كود C #:
 if (user != null && user.parent != null && user.parent.parent != null) { user.parent.parent.SetName(""); } 
بمساعدته ، يمكن إعادة كتابة قسم التعليمات البرمجية هذا على النحو التالي:
 user?.parent?.parent?.SetName(""); 
في JavaScript ، عادة ما يتم على النحو التالي:
 user && user.parent && user.parent.parent && user.parent.parent.setName(""); 
تحديد القيم الافتراضية
هناك عملية شائعة أخرى هي تعيين القيم الافتراضية ، من الإصدار 2.0 في C # Null Coalescing Operator ظهر - ?? .
السطرين التاليين من رمز C # متساويان:
 var name = user != null && user.name != null ? user.name : ""; var name = user?.name ?? ""; 
في JavaScript ، يتم إجراء عملية مماثلة على النحو التالي.
 var name = user && user.name || ""; 
ومع ذلك ، يمكننا استخدام عوامل التشغيل && و || فقط إذا كانت 0 و false والسلسلة الفارغة ليست قيمًا صالحة.
في المستقبل المنظور ، مشغلي ?. ، ?? يجب أن تظهر في جافا سكريبت (لقد اجتازوا الآن المرحلة 0) ، يمكن العثور على مزيد من التفاصيل حول هذه العوامل في جافا سكريبت في المقالة .
هذه الكلمة
يحتوي كل من C # و JavaScript على this . عادة في C # فهم الغرض من this هو مباشر ، ولكن في JavaScript هذا هو واحد من أكثر مفاهيم اللغة تعقيدا. علاوة على ذلك ، سننظر في تطبيق this على الأمثلة.
في 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 هو المثيل الحالي للفئة ، فلا يمكن استخدامه في طرق غير مرتبطة بنوع معين ، على سبيل المثال ، في الأساليب الثابتة.
في JavaScript ، يسمى هذا سياق المكالمة وسيتم تحديده عندما يتم استدعاء الوظيفة. إذا قمت بتشغيل نفس الوظيفة في سياق كائنات مختلفة ، فستتلقى وظيفة مختلفة:
 var user = { firstName: "" }; var admin = { firstName: "" }; function func() { alert( this.firstName ); } user.f = func; admin.g = func; // this    : user.f();  
بالإضافة إلى ذلك ، في JavaScript ، هناك إمكانية لتحديد قيمة 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)();//  
إعادة الهيكلة
غالبًا ما يكون من الضروري تعيين العديد من حقول الكائن للمتغيرات المحلية. على سبيل المثال ، كم مرة تلاحظ فيها رمز مشابه؟
 void Method(User user) { var firstName = user.FirstName; var lastName = user.LastName;  
لهذه الأغراض ، يمكنك استخدام التدمير. تدعم كلتا اللغتين هذه الميزة بدرجات متفاوتة.
قدم C # 7.0 نوعًا جديدًا من الوظائف يسمى أدوات التفكيك لدعم التدمير. من أجل الإعلان عن أداة التفكيك ، نحتاج إلى تعريف طريقة تسمى Deconstruct ، والتي يجب الإعلان عن جميع معلماتها مع معدِّل out :
 class Person { public string FirstName { get; set; } public string LastName { get; set; }  
ظهر دعم التدمير أو (مهمة التدمير) في JavaScript في معيار EcmaScript السادس. بمساعدتها. يمكنك تعيين مصفوفة أو كائن لعدة متغيرات في وقت واحد ، وتقسيمه إلى أجزاء.
 let [firstName, lastName] = ["", ""]; let [firstName, _ ] = ["", ""]; let { firstName, lastName } = { firstName: "", lastName: "" }; let { firstName } = { firstName: "", lastName: "" }; 
تجدر الإشارة إلى أن إعادة الهيكلة في JavaScript لها ميزات أكثر من C #:
- تغيير ترتيب المتغيرات ؛
- لا حاجة إلى التصريح الصريح بفواصل التفكيك ؛
- صفيف دعم التدمير ؛
- تحديد القيم الافتراضية ؛
- تعيين خصائص كائن لمتغير باسم مختلف ؛
- دعم التدمير المتداخل.
الخلاصة
في هذه المقالة ، ناقشنا فقط المفاهيم الأساسية للغات C # وجافا سكريبت. لكن العديد من الجوانب ظلت غير متأثرة:
- مجموعات
- الوظائف
- الطبقات
- تعدد المواضيع
كل واحد من هذه المواضيع واسع النطاق وسيتم الكشف عنه لاحقًا في مقالة منفصلة.