بُنيت jQuery على لغة جافاسكريبت، وهي لغةٌ غنيّة وقويّة في حدّ ذاتها. يُغطّي هذا الدّرس أساسيّات لغة جافا سكريبت، وبعض الأخطاء الشّائعة الّتي يرتكبها المبتدئون بها. يُفيد هذا الدّرس القادمين الجدد إلى عالم البرمجة، ويفيد أيضًا المبرمجين بلغات أخرى الّذين لم يسبق لهم الاطّلاع على الجوانب المميّزة لـJavaScript.
فيما يلي برنامج JavaScript بسيط يُضيف رسالةً إلى صفحة ويب:
// أنشئ دالّة لإلقاء التّحية على شخص // وأسندها إلى المُتغيّر `greet` var greet = function( person, message ) { var greeting = 'Hello, ' + person + '!'; log( greeting + ' ' + message ); }; // استخدم الدالّة لتحيّة Jory، بإمرار اسمها ورسالة التّحيّة greet( 'Jory', 'Welcome to JavaScript' ); // استخدم الدالّة لتحيّة Rebecca، بإمرار اسمها ورسالة مختلفة greet( 'Rebecca', 'Thanks for joining us' );
مُلاحظة: في المثال السابق، استخدمنا الدّالّة log
. وهي دالّة مُساعِدة متوفّرة في الأمثلة في هذه السّلسلة فقط، وليست متوفّرة تلقائيًّا في JavaScript، يمكن استخدام log
في محرّر النّصوص البرمجيّة في هذه السّلسلة، ولكن ستحتاج إلى استخدام console.log
محلّها في النّصوص البرمجيّة خارج السّلسلة، وعندها ستُطبع نتائج النّصّ إلى طرفيّة المتصفّح الّذي تستعمله.
// create a function that will greet a person, // and assign the function to the `greet` variable var greet = function( person, message ) { var greeting = 'Hello, ' + person + '!'; log( greeting + ' ' + message ); }; // use the function to greet Jory, passing in her // name and the message we want to use greet( 'Jory', 'Welcome to JavaScript' ); // use the function to greet Rebecca, passing in her // name and a different message greet( 'Rebecca', 'Thanks for joining us' );
المثال السابق يعرض نتيجة تنفيذ النّص البرمجيّ ضمن قسم Console، يمكنك إعادة ضبط المثال باستخدام الزر Clear ثمّ تعديل النصّ إن رغبت بالتجربة وإعادة تنفيذه بنقر Run. لا بأس إن بدت بعض الأشياء غير مفهومة الآن؛ ففي الفقرات التّالية سنطّلع على مفاهيم المتغيّرات والدوالّ والمكوّنات الأساسيّة الأخرى لـJavaScript.
ملاحظة عن التعليقات
تفيد التّعليقات في شرح ما يفعله كل جزء من النصّ البرمجيّ، ولا تؤثّر التعليقات في عمل البرنامج على الإطلاق. بعض المُبرمجين يحبّون الإكثار من التعليقات في برامجهم، بينما يفضّل آخرون كتابتها فقط عندما تكون بعض الأجزاء من النّصّ غامضة ولا تتضّح بسهولة.
تسمح JavaScript بنوعين من التعليقات: مفردة السّطر، ومتعدّدة السّطور، ويبدأ الشّكل الأوّل بالحرفين //
؛ بينما يبدأ الثّاني بالحرفين /*
وينتهي بـ*/
.
// هذا تعليق مُفرد السّطر var foo; /* هذا تعليقٌ متعدّد السّطور يمكن أن يمتدّ على أكثر من سطر، كما ترى. */
يمكن أيضًا استخدام التّعليقات متعدّدة السّطور مُضمّنة ضمن سطرٍ من النّصّ البرمجيّ:
function cornify( unicorns /* عدد صحيح */, rainbows /* عدد صحيح */ ) { }
المكوّنات الأساسيّة لـJavaScript
المُتغيِّرات (Variables)
المُتغيّرات هي الطّريقة الّتي نخزّن بها القيم الّتي نريد استخدامها في وقت لاحقٍ. يمكن أن تكون المتغيّرات على عدّة أنواع من نصوصٍ أو أعداد أو بياناتٍ أخرى كالمصفوفات والكائنات، أو حتى نصوصًا برمجيّة (بصورة دالّة مُخزّنة في متغيّر). يُصرّح عن المتغيّر بجملة var
:
var myName = 'Rebecca';
يمكن اختيار أي اسم للمتغيّر بشرط ألّا يبدأ الاسم برقمٍ وألّا يحوي إشارة النّاقص "-".
بإمكانك التّصريح عن متغيّر واحدٍ في كلّ جملة:
var a = 1; var b = 'two';
أو التّصريح عن عدّة متغيّرات في جملة واحدة بفصلها بفواصل لاتينيّة:
var a = 1, b = 'two';
بعد إسناد قيمة للمتغيّر، يمكن استخدام هذا المتغيّر للوصول إلى القيمة المُخزّنة فيه:
log( myName ); // يطبع 'Rebecaa'
المتغيّرات مكوّن ضروريّ للالتزام بمبدأ "لا تكرّر نفسك" (Don't Repeat Yourself)، فإذا أردت استخدام قيمة واحدة أكثر من مرّة، فالغالب أنّك ترغب في تخزينها في مُتغيّر.
سنتحدّث عن المتغيّرات بتفصيل أكبر في الفقرة القادمة.
الدّوالّ (Functions)
الدّوال مكوّن أساسيّ في برامج JavaScript لأنّها توفّر وسيلة لتهيئة وظائف صغيرة في البرنامج بصورة جزء مستقلّ ومنظّم. افترض مثلًا دالّة تجمع عددين:
function(a, b) { return a + b; }
تأخذ هذه الدّالة مُعاملين اثنين هما a
وb
، تجمعهما ثمّ تعيد المجموع كنتيجة الدّالّة.
المثال السّابق هو برنامج JavaScript سليم الصّياغة، لكنّه لا يفعل شيئًا على الإطلاق، لأنّه ما من طريقة تسمح لنا بأن نطلب من هذه الدّالة أن تجمع أي عددين بعدُ. علينا إذًا إيجاد طريقة لاستدعاء الدّالّة، ويمكننا فعل ذلك بإسنادها أولًّا إلى متغيّر:
var addTwoNumbers = function(a, b) { return a + b; }
ما فعلناها في المثال الأخير هو أنّنا أخذنا تعبيرًا عن دالّة (function expression) وأسندناه إلى مُتغيّر. يمكننا الآن استدعاء هذه الدّالة باستخدام اسم المتغيّر:
log( addTwoNumbers(1, 1) ); // تطبع 2
يمكننا بدلاً من ذلك استخدام تصريح عن دالّة (function declaration) لإعطاء دالّتنا اسمًا:
function addTwoNumbers(a, b) { return a + b; }
وكلا الطّريقتين تسمحان لنا باستدعاء دالّتنا بالأسلوب نفسه، ولكن يجب الحذر عند اعتماد الأسلوب الأخير لأسباب تشرحها هذه التّدوينة.
الخلاصة: تسمية الدّوالّ بالتّصريح عن الدّالّة قد تؤدّي إلى نتائج غير مُتوقّعة إن لم تفهم بدقّة إحدى ميّزات JavaScript المعروفة باسم "الرّفع إلى أعلى النّطاق" (hoisting). تفصيل هذه الميزة موضوعٌ خارج عن نطاق هذه السّلسلة، ولكنّنا سنعتمد إسناد الدّوال إلى المُتغيّرات في الوقت الحاليّ.
الدّوال ونطاق المُتغيّرات (Variable scope)
تكون المُتغيّرات الّتي تُعرَّف ضمن دالّة بجملة var
مُتاحة فقط من داخل هذه الدّالّة، وهذا أمر مرغوبٌ عادةً، ولذا يجب التّصريح عن كلّ المُتغيّرات في البرنامج باستخدام جمل var
ما لم يُقصد جعلها عامّة (global)، أي متاحةً عبر كامل البرنامج وفي أيّ موضع منه. ليس هذا ما نُريده عادةً إلّا إذا أردنا تغيير قيمة المُتغيّر من نصّ برمجيّ آخر.
ولكن ما معنى أن تكون المُتغيّرات مُتاحةً فقط داخل الدّالّة؟ جرّب هذا البرنامج:
تحذير: نصّ برمجيّ خاطئ
var myFunction = function() { var foo = 'bar'; }; myFunction(); log( typeof foo ); // تطبع undefined!
لو أنّنا حاولنا في المثال السّابق استخدام قيمة foo
خارج الدّالة (بدل الاكتفاء بفحص نوعها)، لأبلغنا المُتصفّح بوجود خطأ، ولن يتابع البرنامج العمل فيما يلي الموضع الّذي استخدمنا foo
عنده.
المثال التّالي يبيّن كيف يمكن لمُتغيّرين مختلفين أن يوجدا باسمٍ واحد طالما أنّ كلًّا منهما موجود في نطاق منفصل عن الآخر. في هذا المثال نُصرّح عن المُتغيّر foo
ونسند إليه القيمة 'qux'
، ثم نُصرّح عن مُتغيّر آخر داخل دالّة، ونُسمّيه foo
أيضًا، ونُسند إليه القيمة 'bar'
. لاحظ أنّ المُتغيّر foo
خارج الدّالة لا يتغيّر حتّى بعد أن نُنشئ المُتغيّر foo
داخل الدّالة.
var foo = 'qux'; var myFunction = function() { var foo = 'bar'; }; log( foo ); // تطبع 'qux' myFunction(); log( foo ); // تطبع 'qux' أيضًا
على الرّغم من تشارك المُتغيّرين اسمًا واحدًا، إلّا أنّ JavaScript تعتبرهما شيئين مختلفين بالكامل، وهذا واحد من عدّة أسباب تدفعك لإعطاء مُتغيّراتك أسماء مُعبّرة.
نطاق المُتغيّرات مفهوم جوهريّ في JavaScript، ولعلّه يسبّب بعض الارتباك للمبتدئين. تذكّر:
- في الأغلبية السّاحقة من الحالات، صرّح عن المُتغيّرات بجملة
var
- لا يمكن الوصول إلى المُتغيّرات المفروضة داخل دالّة بجملة
var
من خارج هذه الدّالّة - المُتغيّرات الّتي تُفرض بلا جملة
var
تكون عامّةً دائمًا
انتبه إلى أنّ المُتغيّرات الّتي يُصرَّح عنها بلا الكلمة var
تكون ضمنيًّا عامّةً. في المثال التّالي لدينا المُتغيّر a
المتاح خارج الدّالة لأنّ عُرِّف بدون الكلمة var
(وهذا أمرٌ غير مرغوب في معظم الحالات).
تحذير: نصّ برمجيّ غير آمن
function test() { a = 1; } test(); log( a ); // تطبع 1
الكائنات (Objects)
الحقيقة أنّ معظم ما نتعامل معه في JavaScript ليس سوى كائنات، وليس في اللّغة إلّا 5 أنواع من القيم الّتي لا تُعتبر كائنات:
- السلاسل النّصيّة (strings)
- القيم المنطقية (true/false)
- الأعداد
undefined
(غير مُعرّف)null
(معدوم)
تُسمّى القيم السّابقة بالأنواع الأوّليّة (primitives)، ويمكن حتّى لبعض هذه القيم أن تُعامل كما لو أنّها كائنات (سنشرح هذا بعد قليل). ولكن ما الكائن؟ لنُلقِ نظرةً على كائنٍ بسيط:
var person = { firstName: 'Boaz', lastName: 'Sender' };
للكائن الّذي أنشأناه أعلاه خاصّتان اثنتان (properties): firstName
وlastName
. أنشأنا الكائن بصياغة "الكائن الحرفيّ (object literal)" أي بإحاطة مجموعة من أزواج مفتاح/قيمة بقوسين معكوفين {}
. لاحظ أنّ نقطتين (:
) تفصلان بين المفتاح والقيمة وأنّ فاصلة لاتينيّة (,
) تفصل بين كلّ زوجين. لاحظ أنّه ما من فاصلة بعد الزّوج الأخير، وإن أضفتها سهوًا فستقع أخطاء عند تنفيذ البرنامج في المتصفّحات القديمة.
الوصول إلى الخصائص
حفظنا الكائن في مُتغيّر أسميناه person
، ممّا يُسهّل الوصول إلى خصائصه، إمّا باستخدام أسلوب النّقاط (dot notation) أو أسلوب الأقواس المُربّعة (bracket notation).
var person = { firstName : 'Boaz', lastName : 'Sender' }; log( 'First name: ' + person.firstName ); // dot notation log( 'Last name: ' + person[ 'lastName' ] ); // bracket notation
ستلاحظ أنّنا استخدمنا سلسلة نصّيّة (string) للوصول إلى اسم الخاصّة الّتي نريدها عند اعتماد أسلوب الأقواس المُربّعة. أمّا عند اعتماد الأسلوب الآخر، أسلوب النّقاط، فقد استخدمنا اسم الخاصّة نفسه دون علامتي الاقتباس. يفيد أسلوب الأقواس المُربّعة عندما نريد الوصول إلى خاصّة يُحفَظ اسمها ضمن مُتغيّر:
var person = { firstName : 'Boaz', lastName : 'Sender' }; var prop = 'lastName'; log( 'Last name: ' + person[ prop ] );
بعد أن أنشأنا الكائن، يمكننا تعديل خصائصه:
var person = { firstName : 'Boaz', lastName : 'Sender' }; person.firstName = 'Ben'; person.lastName = 'Alman'; log( 'First name: ' + person.firstName ); log( 'Last name: ' + person.lastName );
هذا الجانب في JavaScript هو نعمة ونقمة في الوقت ذاته، فهو يعني أنّ الكائنات مرنة بصورة فائقة، ولكنّه أيضًا يعني أنّه ما من "خصوصيّة" للكائنات، فيمكن لأيّ نصّ برمجيّ أن يُسند قيمةً جديدة إلى أيّ خاصّة في أيّ كائن يمكنه الوصول إليه؛ وهذا سبب آخر يدفعك للاحتفاظ بالمُتغيّرات معزولةً عن النّطاق العامّ إلّا إذا كنت تريد فعلًا للبرامج الأخرى أن تُغيّر تلك الخصائص.
وظائف الكائنات (Object methods)
الوظائف (methods) هي خصائص في الكائن قيمها دوالّ (functions)، لنُضِف وظيفة .greet()
إلى كائن person
:
var person = { firstName : 'Boaz', lastName : 'Sender', greet : function(name) { log( 'Hi, ' + name ); } }; person.greet( person.firstName );
استقبلت الوظيفة .greet()
في المثال السّابق النّصّ name
كُمعامِل لها. عند استدعاء هذه الدّالة، أرسلنا قيمة الخاصّة firstName
لكائن person
ببساطة. لو أردنا وظيفة فائقة المُرونة تُلقي التّحيّة على أيّ شخص، فلرّبما يكون ما كتبناه صحيحًا. ولكن الغالب أنّنا نريد لوظيفتنا أن تُلقي التّحيّة على الشّخص المُحدّد في الكائن person
فقط.
معنى this
داخل كلّ وظيفة (وداخل كلّ دالّة) تتوفّر كلّمة مفتاحيّة خاصّة: this
، وهي تُشير إلى الكائن الّذي يُمثِّل السّياق الّذي اُستدعيت فيه الدّالة.
عندما نستدعي person.greet()
يكون السّياق هو الكائن person
ذاته. معنى هذا أنّ بإمكاننا استخدام this
للوصول إلى إحدى خصائص الكائن person
مباشرة من داخل الوظيفة .greet()
.
ملاحظة: معنى this
قد يُسبّب ارتباكًا شديدًا لمطوّري JavaScript المُبتدئين، يمكنك الاطمئنان إن لم تفهم بدقّة معناها، لأنّ jQuery تُحسن استغلالها بحيث لا تضطّر للدّخول في تفاصيلها؛ ومع ذلك فلا يكتمل الحديث عن الكائنات ووظائفها دون الإشارة إلى this
وإن قليلًا. سأترك لك حرّيّة الانتقال إلى فقرة "الكائنات في jQuery" من هذه المقالة إن شئت، ثمّ عُد إلى هنا عندما تشعر أنّك جاهز لفهمها تمامًا.
لنحاول فهم كيف يمكن استخدام this
في وظيفتنا:
var person = { firstName : 'Boaz', lastName : 'Sender', greet : function() { log( 'Hi, ' + this.firstName ); } }; person.greet();
ليست مُعقّدةً كثيرًا حتى الآن... صحيح؟ منشأ التّعقيد هو أنّ معنى this
يمكن أن يتغيّر، فالأمر كما قلنا يعتمد على السّياق الّذي استدعيت فيه الدّالة! لاحظ النّصّ التّالي:
تحذير: نصّ برمجيّ خاطئ
var person = { firstName : 'Boaz', lastName : 'Sender', greet : function() { log( 'Hi, ' + this.firstName ); } }; var sayIt = person.greet; // store the method in a variable sayIt(); // logs 'Hi, undefined' -- uh-oh
عندما نحفظ الوظيفة .greet()
في مُتغيّر sayIt
ثمّ نستدعي sayIt()
، فإنّ السّياق يتغيّر ليُصبح الكائن العامّ window
، لا الكائن person
. وبما أنّ ليس للكائن window
خاصّة اسمها firstName
، فإنّ النتيجة تكون undefined
عندما نحاول الوصول إليها.
ما الذي على المُبرمج فعله إذًا؟ أوّلًا: عليه أن يحذر من النّتائج غير المُتوقّعة لمعنى this
عند تخزين وظائف الكائنات في متغيّرات. وثانيًا: عليه أن يعلم أنّ بإمكانه إجبار this
أن تُشير إلى ما يشاء من الكائنات وذلك باستخدام إحدى الوظيفتين .call()
و.apply()
مع الدّالّة ذاتها.
var person = { firstName : 'Boaz', lastName : 'Sender', greet : function() { log( 'Hi, ' + this.firstName ); } }; var sayIt = person.greet; sayIt.call( person );
كلا الوظيفتين المُتشابهتين .call()
و.apply()
تُتيحان إمرار المُعاملات إلى الدّالّة الّتي تُستدعى بهما. تخيّل أنّ دالة التّحيّة تقبل بعض المعاملات، يمكن حينئذٍ إمرار هذه المُعاملات باستخدام .call()
كما يلي:
var person = { firstName : 'Boaz', lastName : 'Sender', greet : function(greeting, punctuation) { log( greeting + ', ' + this.firstName + punctuation ); } }; var sayIt = person.greet; sayIt.call( person, 'Hello', '!!1!!1' );
يمكن تنفيذ الأمر ذاته باستخدام .apply()
، ولكن سنحتاج معها إلى إمرار المُعاملات ضمن مصفوفة واحدة بدلًا من إمرارها مُنفصلة:
var person = { firstName : 'Boaz', lastName : 'Sender', greet : function(greeting, punctuation) { log( greeting + ', ' + this.firstName + punctuation ); } }; var sayIt = person.greet; sayIt.apply( person, [ 'Hello', '!!1!!1' ] );
مُلاحظة: لتفاصيل أكثر عن .call()
و.apply()
، راجع وثيقتي شبكة مُطوِّري موزيلّا .call()
و.apply()
،
الكائنات في jQuery
لم نتطرّق بعدُ إلى تفاصيل الكائنات في JavaScript لكنّك الآن تعرف الأساسيّات الّتي تُتيح لك التّعامل مع الكائنات خلال تعلّمك jQuery، ففيها ستستعمل الكائنات لضبط الخيارات، كتغيير عدّة خصائص CSS لعنصر في الصّفحة مرّة واحدة:
$('#main').css({ color: 'red', border: '1px solid blue' });
بخصوص this
، فإنّ jQuery
تُسيطر على معناها، وفي حالة مُتولّيات الأحداث (event handlers)، تُشير this
إلى العنصر في الصّفحة الّذي ربطتّه بالمُتولّي، وفي حالة سرد مجموعة من الكائنات في تحديدٍ، تُشير this
إلى العنصر الحاليّ في السّرد. ليس عليك الحرص على فهم this
بدقّة في المراحل الأولى لتعلّمك، بل اكتفِ بإبقاء فكرتها في ذهنك أثناء تعلّمك.
تفاصيل أكثر
يتوسّع دليل JavaScript في شبكة مُطوِّري موزيلّا في شرح مواضيع مثل النّماذج البدئيّة للكائنات (object prototypes) والدّوال المُشيِّدة (constructor functions) وحذف خصائص الكائنات.
المصفوفات (Arrays)
المصفوفات نوعٌ من الكائنات تُستخدم لحفظ قائمة من القيم، وهي وسيلةٌ سهلة لتخزين مجموعة من العناصر المترابطة من نفس النّوع (كالسّلاسل النّصيّة)، مع أنّ الواقع أنّه لا شيء يمنع مصفوفةً من أن تحوي عدّة أنواع من العناصر، بما في ذلك مصفوفاتٍ أخرى.
الطّريقة المُفضّلة لإنشاء مصفوفة استخدامُ أسلوب المصفوفات الحرفيّة:
var myArray = [ 'a', 'b', 'c' ];
ملاحظة: ستقرأ من وقتٍ لآخر برامج تُنشئ المصفوفات بالأسلوب التالي: new Array('a', 'b', 'c')
وهو أسلوب غير مقبولٍ وسط مُطوّري JavaScript لأنّه لا يختلف عن الأسلوب الأوّل سوى في أنّ له عيوبًا ليست في الأوّل! فمثلاً: كتابة new Array(3)
تعني إنشاء مصفوفة فيها ثلاث عناصر كلّها غير مُعرّفة، بدلاً من إنشاء مصفوفة فيها العدد 3 (أي بدلًا من [ 3 ]
).
يمكن الوصول إلى خصائص المصفوفات (الّتي تُسمّى أحيانًا بعناصر المصفوفة (elements)) باستخدام صياغة الأقواس المربّعة ذاتها المستخدمة مع الكائنات، فكلّ عنصر يُعطى اسما تلقائيًّا بحسب موقعه في المصفوفة. ولكن عليك الحذر: فالأعداد تبدأ من الصّفر. لنُلق نظرة على مصفوفة فيها 3 عناصر:
تحذير: أسلوب غير مُفضّل
var myArray = [ 'a', 'b', 'c' ]; var firstItem = myArray[ "0" ]; // الوصول إلى العنصر الأوّل
عند الوصول إلى عناصر المصفوفة، فإنّه من الأسهل استخدام الأعداد لتحديد موضع العنصر المطلوب في المصفوفة، والّذي يُسمّى الدّليل (index):
var myArray = [ 'a', 'b', 'c' ]; var firstItem = myArray[ 0 ]; var secondItem = myArray[ 1 ]; // access the item at index 1 log( secondItem ); // logs 'b'
يمكننا معرفة عدد العناصر في مجموعة بالوصول إلى الخاصّة length
في المصفوفة:
var myArray = [ 'a', 'b', 'c' ]; var len = myArray.length; log( len ); // logs 3
حلقات for
: سرد المصفوفات
بما أنّنا نعلم كيف نحدّد طول المصفوفة (عدد العناصر فيها)، وأنّ أوّل عناصرها يقع عند الدّليل 0
، يمكننا إذن سرد عناصر المصفوفة باستخدام حلقة for
:
يمكننا فعل الكثير من الأشياء بالمصفوفات، راجع وثيقة المصفوفات في شبكة مُطوِّري موزيّلا للاطّلاع على الدّليل الكامل.
المنطق والتّحقّق من الصّحِّة
تُوفِّر JavaScript الكلمتين if
وelse
، وكذلك المُعامل الثّلاثي، للسّماح بتنفيذ بعض الأوامر فقط عند تحقّق شروط معيّنة. تُحدّد JavaScript توفّر شرطٍ ما بتحرِّي "صحِّة" قيمة أو عبارة. ولأنّ JavaScript لُغةٌ متغيّرة الأنواع (dynamically typed)، فإنّ بإمكاننا استخدام أيّة قيمة أو أي تركيبٍ من القيّم، إلّا أنّ قواعد التّحقّق من كون قيمةٍ مُعيّنة أو عبارةٍ معيّنة صحيحةً (true
) أو خاطئة (false
) قد تُسبّب بعض الارتباك.
فيما يلي مثال عن جملة شرطيّة (if
) بسيطة في JavaScript. تتحرّى الجملة من صحِّة العدد 1
؛ ولأنّ 1
قيمة "صائبة" (truthy)، فسيُنفَّذ النّص البرمجيّ الواقع بين القوسين المعكوفين {}
بعد جملة if
.
if ( 1 ) { // سيُنفَّذ هذا الأمر log( '1 is truthy' ); }
الحقيقة أنّ معظم القيم في JavaScript "صائبة"، بل إنّ خمس قيمٍ فقط في اللّغة تُعتبر "خاطئة" (falsy):
undefined
(القيمة المبدئيّة لكّل مُتغيّر يُفرض دون إسناد قيمة إليه)null
NaN
(ليس عددًا "not a number")0
(العدد صفر)''
(سلسلة نصّيّة فارغة)
عندما نريد تحرّي "خطأ" قيمة ما، نستخدم المُعامل !
:
var a = ''; if ( !a ) { // لن يُنفَّذ هذا الأمر إن كانت a صائبة log( 'a was falsy' ); }
أمّا القيمة NaN
فلها وضعٌ خاصّ، فعند تحرّيها في جملة شرطيّة بسيطة فإنّها خاطئة:
var notANumber = 'four' - 'five'; if ( !notANumber ) { // سيُفَّذ هذا الأمر log( '!notANumber was truthy' ); }
أمّا عندما نقارن القيمة NaN
مع false
، فإنّنا نحصل على قيمة "خاطئة":
var notANumber = 'four' - 'five'; if ( notANumber == false ) { // لن يُنفَّذ هذا الأمر log( 'notANumber was falsy' ); } else { // سُينفَّذ هذا الأمر log( 'notANumber was truthy' ); }
من المهمّ أن نتذكّر أنّ كلّ القيم الأخرى ما عدا الخمس السّابقة تُعتبر صائبة، بما في ذلك المصفوفات الفارغة والكائنات الفارغة وكل السّلاسل النّصيّة غير الفارغة (متضمّنة السلسلة النّصيّة '0'
) وكلّ الأعداد ما عدا 0
.
ملاحظة: من الممكن كتابة جملة شرطيّة فيها if
وelse
في سطر واحدٍ دون استخدام الأقواس المعكوفة، ولكنّ هذه الممارسة غير مفضّلة لأنّها تجعل قراءة البرنامج وصيانته أصعب؛ وما ذكرناها هنا إلّا لأنّها قد تصادفك عند قراءة برامج مطوّرين آخرين.
المُعامِلات المنطقيّة (Logical Operators)
تسمح المُعاملات المنطقيّة بتقييم طرفيّ العمليّة المنطقيّة بتنفيذ عمليتيّ AND (&&
) وOR (||
).
var foo = 1; var bar = 0; var baz = 2; foo || bar; // تُعيد 1 وهي قيمة صائبة bar || foo; // تُعيد 1 وهي قيمة صائبة foo && bar; // تُعيد 0 وهي قيمة خاطئة foo && baz; // تُعيد 2 وهي قيمة صائبة
في حالة المُعامل ||
، تكون القيمة المُعادة هي أوّل قيمة تُثبت صحّة الجُملة، أو آخر قيمة. أمّا في حالة المُعامل &&
فإنّ القيمة المُعادة تكون أوّل قيمة تُثبت خطأ الجملة، أو آخر قيمة.
قد ترى المُعاملات المنطقيّة تُستخدم بأسلوب ذكيّ للتّحكّم بسير البرنامج:
foo && bar(); // استدعِ الدالّة bar فقط عندما تكون foo صائبة var bar = baz || createBar(); // استخدم baz كقيمة لـbar إلّا إن كانت // خاطئة، وعندها أنشئ bar
هذا الأسلوب جميل ومُختصر، ولكنّه قد يزيد قراءة البرنامج صعوبةً، خصوصًا للمبتدئين. عليك أن تتعلّمه لتعرفه في برامج الآخرين، ولكننّني أنصحك بالنأي عن استخدامه في البداية، واستخدام if
وelse
التّقليديّتين لأنّهما أوضح.
المُعامِل الثّلاثي (Ternary Operator)
عادةً ما ترغب بتعيين قيمة مُتغيّر بحسب صحّة شرط معيّن أو خطئِه، بإمكانك بالطّبع استخدام if
وelse
:
تحذير: أسلوب غير مُفضّل
var propertyName; if (dim === 'width') { propertyName = 'clientWidth'; } else { propertyName = 'clientHeight'; }
إلّا أنّ المُعامل الثّلاثيّ يسمح بتحقيق الغاية ذاتها بطريقة بأسلوب أقصر وأوضح:
var propertyName = ( dim === 'width' ) ? 'clientWidth' : 'clientHeight';
تُتحرَّى الجملة قبل ?
لمعرفة صوابها، فإن كانت صائبة أُسندت القيمة الأولى (clientWidth
) إلى المُتغيّر propertyName
، وإلّا أُسنِدت القيمة الثّانية (clientWidth
) إليه.
عثرات JavaScript
بالإضافة إلى نطاقات المُتغيّرات والتّحرّي من الصّحة، هنالك العديد من العثرات الأخرى في JavaScript، وسنلقي نظرة على بعضها.
تسمية الأشياء
تبدأ الأسماء السّليمة في JavaScript بحرف أو برمز مُعيّن، متبوعٍ أو غير متبوع بحروف أو أرقام أو علامات _ أو رموز أخرى. لا يمكن أن تبدأ الأسماء بأرقام أو أن تتضمّن إشارة النّاقص (-). سمِّ المتغيرات بالأسماء الّتي تحلو لك طالما التزمت بهذه القواعد، وهذه الأسماء كلّها سليمة:
a
a1
foo_bar
fooBarBaz
$fooBar
_foo
__foo__
وضع مجتمع JavaScript بعض الأعراف الشّائعة لتسمية المُتغيّرات والخصائص في JavaScript، لكنّها مُجرَّد أعراف، فهي ليست إلزاميّة، ولا تؤثّر في عمل البرنامج:
- الأسماء الّتي تبدأ بـ
_
تُشير عادةً إلى قيم سرِّيَّة (private) (سنوضِّح ذلك لاحقًا). - الأسماء الّتي تبدأ بحرف كبير هي عادةً دوال مُشيّدة (constructors) تُستخدم لإنشاء نُسخ جديدة من الكائنات (سنوضّح ذلك لاحقًا أيضًا).
- في البرامج الّتي تستخدم jQuery، الأسماء الّتي تبدأ بالرّمز
$
تُشير عادّة إلى كائنات jQuery.
الكلمات المحجوزة (Reserved words)
تحتفظ JavaScript لنفسها ببعض الكلمات الّتي يفضّل اجتنابها كأسماء لمكوّنات برامجك:
abstract boolean break byte case catch char class const continue debugger default delete do double else enum export extends false final finally float for function goto if implements import in instanceof int interface long native new null package private protected public return short static super switch synchronized this throw throws transient true try typeof var volatile void while with
فإنّ كان لا بدّ من استخدامها كاسم لخاصّة كائن، فعليك إحاطتها بعلامتي اقتباس:
var myObject = { 'class': 'tasty' };
العمليّات على الأعداد والسّلاسل النّصيّة
التّعامل مع الأرقام في JavaScript قد يُعطي نتائج غير متوقّعة أحيانًا، بسبب طريقة تمثيل الأرقام داخليًّا في JavaScript، فمثلاً: عند جمع عددين عشريّين، تكون النّتيجة عدًدا قريبًا جدًّا من القيمة المتوقّعة، لكنّه غير مساوٍ تمامًا:
log( 0.0001 + 0.0002 ); // 0.00030000000000000003
لن تصادف هذا كثيرًا عند العمل مع jQuery، ولكنّها قضيّة مهمّة يجب الانتباه لها خصوصًا عندما تتعامل مع أرقامٍ عشريّة كالعملات. عندما تُجري عمليّات حسابيّة تحتاج دقّة تامّة، فعليك تحويل القيم إلى أعداد صحيحة قبل العمل بها، ثمّ تحويلها ثانيةً إلى أعداد عشريّة بعد الانتهاء.
تتسامح JavaScript مع اختلاف الأنواع، فعند إجراء عمليات حسابية باستخدام قيم غير عدديّة، فلن تُبلغك JavaScript بوجود خطأ، بل ستُتابع العمليّة مُعطيةً نتائج قد لا تتوقّعها:
log( 'a' + 2 ); // 'a2' log( '4' + 3 ); // '43' log( 'five' - '4' ); // NaN (not a number) log( - '1' ); // -1 log( 1 + true ); // 2 log( 1 == true ); // true log( 1 === true ); // false
مطالعة
لم نخض في أعماق لغة JavaScript بعدُ. شبكة مُطوّري موزيلّا (MDN) مصدر ممتاز (بالإنكليزيّة) لتعلّم JavaScript بتفاصيلها، وخصوصًا دليل JavaScript على الشّبكة. أكثر المواضيع أهمّيّة لك الآن:
- نظرة عامّة على JavaScript
- القيم والمتغيّرات والمكوّنات الحرفيّة
- الدّوالّ
- عبارات الدّوالّ المُستدعاة فورًا
- المصفوفات
مصادر إضافية
- شبكة مُطوّري موزيلّا: JavaScript
- Chrome Developer Tools Overview
- Fixing these jQuery: A Guide to Debugging
- Chrome Developer Tools Cheat Sheet
- Chrome Dev Tools: 12 Tricks to Develop Quicker (فيديو)
ترجمة (بشيء من التصرف) للجزء الأول من سلسلة jQuery Fundamentals لمؤلّفتها Rebecca Murphey.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.