
بدأت مسيرتي الأكثر أو الأقل خطورة في البرمجة بكتابة برامج في 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 # وجافا سكريبت. لكن العديد من الجوانب ظلت غير متأثرة:
- مجموعات
- الوظائف
- الطبقات
- تعدد المواضيع
كل واحد من هذه المواضيع واسع النطاق وسيتم الكشف عنه لاحقًا في مقالة منفصلة.