سجى الحاج

الأعضاء
  • المساهمات

    7
  • تاريخ الانضمام

  • تاريخ آخر زيارة

السُّمعة بالموقع

1 Neutral
  1. نحتاج في بعض الأحيان إلى تنفيذ إجراءات مختلفة بناءً على شروط مختلفة. للقيام بذلك، يمكنك استخدام التعبير الشرطي if والمعامل الشرطي ? الذي يسمى أيضًا «معامل علامة استفهام» (question mark operator، أو المعامل الثلاثي كما سنرى من صياغته). التعبير الشرطي if يُقيّم التعبير الشرطي if شرطًا، فإذا تحقَّق true، فيُنفِّذ مجموعة من الشيفرات البرمجية. على سبيل المثال: let year = prompt('In which year was ECMAScript-2015 specification published?', ''); if (year == 2015) alert( 'You are right!' ); في المثال أعلاه، يكون الشرط عبارة عن فحص بسيط لعملية المساواة year == 2015، ولكنه قد يصبح أكثر تعقيدًا. إذا كنت ترغب في تنفيذ أكثر من تعبير واحد، يجب أن تضع الشيفرة المطلوبة داخل الأقواس المعقوصة {}: if (year == 2015) { alert( "That's correct!" ); alert( "You're so smart!" ); } من الأفضل استخدام الأقواس المعقوصة {} في كل مرة تستخدم فيها التعبير الشرطي if، حتى إذا كنت تريد تنفيذ تعبير واحد فقط لأنَّها تُسهِّل قراءة الشيفرة. التحويل المنطقي يُقيِّم التعبير الشرطي if التعبير الموجود بين القوسين، ثم تُحوّل النتيجة إلى قيمة منطقية. هل تتذكر قواعد التحويل من الفصل التحويل بين الأنواع؟ إذن، لنتذكرها سويةً: يُحوَّل العدد 0، والسلسلة النصية الفارغة ""، و null، و undefined، وNaN جميعها إلى القيمة false. يُطلَق عليها بسبب ذلك «قيم زائفة خاطئة» (falsy values). تُحوَّل القيم الأخرى (أي باستثناء ما سبق) إلى القيمة المنطقية true، لذلك يطلق عليها «القيم الصادقة الصحيحة» (truthy values). لذلك، لن تُنفَّذ الشيفرة البرمجية التالية بناءً على الشرط المعطى: if (0) { // false القيمة 0 تُقيَّم إلى القيمة ... } بينما ستُنفَّذ شيفرة الشرط التالي: if (1) { // true ألقيمة 1 تُقيَّم إلى القيمة ... } يمكنك أيضًا تمرير قيمة منطقية قُيِّمَت مسبقًا إلى الشرط if بالشكل التالي: let cond = (year == 2015); // قيمة عملية التحقق من المساواة هي قيمة منطقية if (cond) { ... } الكتلة الشرطية else قد يحتوي التعبير الشرطي if على كتلة اختيارية تسمى else تُنفذ عندما يكون الشرط غير محقَّق. أي إن تحقق الشرط، فنفِّذ كذا، أو نفِّذ كذا. إليك المثال التالي: let year = prompt('In which year was the ECMAScript-2015 specification published?', ''); if (year == 2015) { alert( 'You guessed it right!' ); } else { alert( 'How can you be so wrong?' ); // أي قيمة باستثناء 2015 } الشروط المتعددة else if تود في بعض الأحيان التحقق من العديد من الحالات لشرط ما. التعبير الشرطي else if (أو إذا كان كذا، فنفِّذ كذا) تفي بهذا الغرض. اطلع على هذا المثال: let year = prompt('In which year was the ECMAScript-2015 specification published?', ''); if (year < 2015) { alert( 'Too early...' ); } else if (year > 2015) { alert( 'Too late' ); } else { alert( 'Exactly!' ); } في الشيفرة أعلاه، تتحقق JavaScript أولاً من الشرط year < 2015. فإذا كان ذلك غير محقَّق، فسيتم الانتقال إلى الشرط التالي year > 2015. وإذا كان هذا أيضًا غير محقَّق، فستُنفَّذ الكتلة المرتبطة بالفرع else أي تُنفَّذ الدالة alert. يمكن أن يكون هناك أكثر من فرع else if، والكتلة الشرطية الأخيرة else اختيارية. المعامل الشرطي ? تحتاج في بعض الأحيان إلى إسناد قيمة لمُتغيِّر وفقًا لشرط ما. يمكن تحقيق ذلك بالشكل التالي: let accessAllowed; let age = prompt('How old are you?', ''); if (age > 18) { accessAllowed = true; } else { accessAllowed = false; } alert(accessAllowed); يتيح لك المعامل الشرطي ? أو «علامة الاستفهام» القيام بذلك بطريقة أقصر وأبسط. يُمثِّل هذا المعامل بعلامة استفهام ?. في بعض الأحيان يُطلَق عليه «المعامل الثلاثي» (ternary)، لأن لديه ثلاثة عاملات (operands) وهو المعامل الوحيد في JavaScript الذي يحتوي على هذا العدد. الصيغة الخاصة به: let result = condition ? value1 : value2; يتم تقييم الشرط condition: إذا كان محقَّقًا، يُرجع value1، عدا ذلك يُرجِع value2. على سبيل المثال: let accessAllowed = (age > 18) ? true : false; من الناحية التقنية، يمكنك حذف الأقواس الموجودة حول age > 18. المعامل الشرطي هذا (أي علامة الاستفهام) له أولوية منخفضة، لذلك يُنفَّذ بعد معامل الموازنة <. يشبه المثال التالي المثال السابق مع اختلاف طفيف جدًا: // أولًا age > 18 يُنفَّذ معامل الموازنة // (لا حاجة لاستخدام الأقواس) let accessAllowed = age > 18 ? true : false; لكن الأقواس تجعل الشيفرة أكثر قابلية للقراءة، لذلك نوصي باستخدامها. ملاحظة: في المثال أعلاه، تجنب استخدام معامل علامة الاستفهام لأنَّ معامل الموازنة نفسه يُرجِع true/false؛ أي المثال السابق يكافئ: let accessAllowed = age > 18; المعامل الشرطي ? المتعدد يمكن لسلسلة من المعاملات الشرطية ? إرجاع القيمة التي تعتمد على أكثر من شرط واحد. اطلع بتفحُّص على المثال التالي: let age = prompt('age?', 18); let message = (age < 3) ? 'Hi, baby!' : (age < 18) ? 'Hello!' : (age < 100) ? 'Greetings!' : 'What an unusual age!'; alert( message ); قد يكون من الصعب فهم الشيفرة السابقة في البداية. ولكن بعد التمعُّن بها قليلًا، يمكنك أن ترى أنَّها مجرد تسلسل عادي من الاختبارات: يتحقق المعامل ? الأول من الشرط age < 3 إذا كان الشرط السابق محقَّقًا، فسيُرجِع Hi, baby!‎؛ خلاف ذلك، فإنَّه يستمر في التحقق من التعبير بعد النقطتين :، ويتحقق من الشرط age < 18. إذا كان الشرط السابق محقَّقًا، فسيُرجِع Hello!‎؛ خلاف ذلك، فإنه يستمر في التحقق من التعبير بعد النقطتين : الثانية، ويَتحقَّق من الشرط age < 100. إذا كان الشرط السابق محقَّقًا، فسيُرجِع Greetings! خلاف ذلك، فإنه يستمر في التحقق من التعبير بعد النقطتين : الأخيرتين، ويتحقق من الشرط What an unusual age!‎. إليك تنفيذ المثال السابق باستخدام if..else فقط: if (age < 3) { message = 'Hi, baby!'; } else if (age < 18) { message = 'Hello!'; } else if (age < 100) { message = 'Greetings!'; } else { message = 'What an unusual age!'; } الاستخدام غير التقليدي للمعامل ? في بعض الأحيان، يُستخدَم معامل علامة الاستفهام ? بديلًا عن المعامل الشرطي if بالشكل التالي: let company = prompt('Which company created JavaScript?', ''); (company == 'Netscape') ? alert('Right!') : alert('Wrong.'); اعتمادًا على الشرط company == 'Netscape'‎، إمَّا أن يُنفَّذ التعبير الأول أو الثاني بعد المعامل ? وتٌظهر الدالة alert القيمة الناتجة بناءً على الشرط. على أي حال، لا نوصي باستخدام معامل علامة الاستفهام ? بهذه الطريقة. الشيفرة السابقة أقصر من شيفرة المعامل الشرطي if المقابلة، الذي يطبقه بعض المبرمجين لكنه يولد شيفرة صعبة القراءة. سنعيد كتابة الشيفرة السابقة باستخدام المعامل الشرطي if: let company = prompt('Which company created JavaScript?', ''); if (company == 'Netscape') { alert('Right!'); } else { alert('Wrong.'); } عند إلقاء نظرة على الشيفرة للوهلة الأولى، من السهل فهم كتل التعليمات البرمجية التي تمتد عموديًّا لعدة أسطر بشكل أسرع من تلك الأفقية الطويلة. الغرض من معامل علامة الاستفهام ? هو إرجاع قيمة ما حسب الشرط المُعطى. يُفضل استخدامه لذلك فقط. استخدم المعامل الشرطي if عندما تحتاج لتنفيذ فروع مختلفة من الشيفرة. .task__importance { color: #999; margin-left: 30px; } .task__answer { border: 3px solid #f7f6ea; margin: 20px 0 14px; position: relative; display: block; padding: 25px 30px; } code { background-color: rgb(250, 250, 250); border-radius: 3px; } تمارين التعبير الشرطي if (سلسلة نصية مع صفر) الأهمية: 5 هل ستُنفَّذ الدالة alert داخل الشرط التالي؟ if ("0") { alert( 'Hello' ); } الحل: نعم، سوف تُنفَّذ وتظهر الرسالة. الغرض من هذا التمرين هو التذكير بأنَّ أي سلسلة نصية باستثناء الفارغة منها (من ضمنها "0" الغير فارغة) تُحوَّل إلى القيمة true في السياق المنطقي. اسم JavaScript الأهمية: 2 باستخدام الصيغة if..else، اكتب الشيفرة التي تسأل: "ما هو الاسم الرسمي لجافاسكربت؟" إذا أدخل المستخدم "ECMAScript"، تخرج الشيفرة "صحيح!"، وإلا - تُخرج: "ألا تعرف؟ ECMAScript!" الحل: <!DOCTYPE html> <html> <body> <script> 'use strict'; let value = prompt('ما هو الاسم الرسمي لجافاسكربت؟', ''); if (value == 'ECMAScript') { alert('صحيح!'); } else { alert("ألا تعرف الاسم الرسمي؟ إنه ECMAScript!"); } </script> </body> </html> إظهار إشارة الأهمية: 2 باستخدام الصيغة if..else، اكتب الشيفرة التي تحصل على عدد عن طريق الدالة prompt ثم أظهر عبر الدالة alert القيمة: 1 إذا كان العدد أكبر من صفر. -1 إذا كان العدد أقل من صفر. 0 إذا كان العدد يساوي الصفر. في هذا التمرين، نفترض أنَّ القيمة المُدخلة دائمًا عدد. الحل: let value = prompt('Type a number', 0); if (value > 0) { alert( 1 ); } else if (value < 0) { alert( -1 ); } else { alert( 0 ); } تحويل التعبير الشرطي if إلى صيغة المعامل ? الأهمية: 5 أعد كتابة التعبير الشرطي if باستخدام المعامل الثلاثي ? if (a + b < 4) { result = 'Below'; } else { result = 'Over'; } الحل: result = (a + b < 4) ? 'Below' : 'Over'; تحويل التعبير الشرطي if..else إلى صيغة المعامل ? الأهمية: 5 أعد كتابة التعبير الشرطي if..else باستخدام المعامل الثلاثي ?. لتسهيل قراءة الشيفرة، يوصى بتقسيمها إلى أسطر متعددة . let message; if (login == 'Employee') { message = 'Hello'; } else if (login == 'Director') { message = 'Greetings'; } else if (login == '') { message = 'No login'; } else { message = ''; } الحل let message = (login == 'Employee') ? 'Hello' : (login == 'Director') ? 'Greetings' : (login == '') ? 'No login' : ''; ترجمة -وبتصرف- للفصل conditional operators من كتاب The JavaScript Language اقرأ أيضًا المقال التالي: المعاملات المنطقية المقال السابق: الدوال التفاعلية: confirm ،prompt ،alert
  2. في هذا الجزء من المقالات التعليمية، نتطرَّق إلى لغة JavaScript كما هي بدون تعديلات خاصة بالبيئة. لكن ما زلنا نستخدم المتصفح كبيئة تجريبية، لذلك يجب أن تتعرف على عددٍ قليلٍ من دوال واجهة المستخدم الخاصة به. ستتعرف في هذا الفصل على هذه الدوال التفاعلية الخاصة بالمتصفح. الدالة alert الصياغة: alert(message); تعرض هذه الدالة رسالة نصية وتوقف تنفيذ السكربت مؤقتًا حتى يضغط المستخدم على «موافق» (OK). إليك الشيفرة البسيطة التالية مثلًا: alert("مرحبًا"); تسمى الرسالة النصية التي تظهر على شكل نافذة صغيرة تدعى «النافذة المنبثقة الشرطية» (modal window، وهي عنصر تحكم رسومي)؛ تعني كلمة «شرطية» أنه لا يمكن للزائر التفاعل مع بقية الصفحة، أو الضغط على أزرار أخرى وما إلى ذلك، إذ تشترط عليه التفاعل معها فقط، أي حتى يضغط على «موافق» (Ok) في هذه الحالة. الدالة prompt تقبل الدالة prompt وسيطين (arguments) لتكون صياغتها بالشكل التالي: result = prompt(title, [default]); تعرض هذه الدالة نافذة منبثقة شرطية مع رسالة نصية مخصصة، وحقل إدخال للمستخدم، وزرَّين (موافق [OK] وإلغاء [CANCEL]). الوسيط title: هو عبارة عن النص الذي سيعرض للمستخدم. الوسيط default: هو وسيط اختياري يمثِّل القيمة الأولية لحقل الإدخال الخاص بالمستخدم. قد يكتب المستخدم شيئًا ما في حقل الإدخال، ثمَّ يضغط على موافق (Ok). أو يمكنه إلغاء الإدخال عند الضغط على إلغاء (CANCEL) أو الضغط على مفتاح الهروب (Esc). استدعاء الدالة prompt يرجع سلسلة نصية تمثِّل القيمة التي أدخلها المستخدم في حقل الإدخال أو يرجع القيمة null إذا تم الخروج من النافذة وإلغائها. جرب نفِّذ المثال التالي في الطرفية وعدل عليه: let age = prompt('كم عمرك؟', 100); alert(`عمرك ${age} سنة!`); في IE (أي المتصفح Internet Explorer)، دائمُا ما يتم إضافة الوسيط default. أي هذا الوسيط اختياري في جميع المتصفحات باستثناء المتصفح IE الذي يعدُّه اجباريًّا، وإذا لم نحدِّد قيمته، يفترض المتصفح Internet Explorer أنَّ قيمته "undefined". نفِّذ هذه الشيفرة في متصفح Internet Explorer لرؤية الناتج: let test = prompt("Test"); لجعل الدالة prompt تعمل جيدًا في المتصفح IE، نوصي دائمًا بتمرير قيمة الوسيط الثاني default: let test = prompt("Test", ''); // <-- IE للمتصفح الدالة confirm الصياغة: result = confirm(question); تُظهر الدالة confirm نافذة منبثقة شرطية تحتوي على سؤال question، وزريّن (موافق [OK] وإلغاء [CANCEL]). تكون النتيجة true إذا ضغط المستخدم على الزر "Ok" وتكون false عدا ذلك. جرِّب المثال التالي في طرفيتك: let isBoss = confirm("Are you the boss?"); alert( isBoss ); الخلاصة ذكرنا في هذا المقال ثلاثة دوال للتفاعل مع مستخدمي الموقع وهي: الدالة alert: تعرض رسالة لإعلام المستخدم بشئ ما، وُتعطل كافة عمليات الصفحة حتى يتفاعل مع هذه الرسالة. الدالة prompt: تعرض رسالة تطلب من المستخدم إدخال شيء ما في حقل إدخال خاص لتعيد القيمة المدخلة في سلسلة نصية، أو ترجع القيمة null إذا تم العملية. الدالة confirm: تعرض رسالة (بمثابة سؤال) وتنتظر من المستخدم الرد عليها بالقبول أو الرفض، أي تكون النتيجة true إذا تم الضغط على زر "Ok" أو تكون false عدا ذلك. كل هذه الدوال مشروطة: فهي تتوقف عن تنفيذ السكربت ولا تسمح للمستخدم بالتفاعل مع بقية الصفحة حتى يتم التفاعل مع النافذة التي تعرضها. هناك اثنين من القيود التي تشترك بها جميع الدوال المذكورة أعلاه: يحدد المتصفح الموقع الذي ستظهر فيه النافذة، وعادة ما يكون في الوسط أو الأعلى. يعتمد شكل النافذة أيضًا على المتصفح، ولا يمكننا تعديله. هذا هو ثمن البساطة. هناك طرق أخرى لإظهار نوافذ أكثر جمالًا وفاعلية، ولكن إذا كانت التنسيقات الجمالية غير مهمة، فهذه الدوال تفي بالغرض. .task__importance { color: #999; margin-left: 30px; } .task__answer { border: 3px solid #f7f6ea; margin: 20px 0 14px; position: relative; display: block; padding: 25px 30px; } code { background-color: rgb(250, 250, 250); border-radius: 3px; } تمارين صفحة بسيطة الأهمية: 4 قم بإنشاء صفحة ويب تطلب اسمًا ما ثم تعرضه. الحل شيفرة JavaScript: let name = prompt("ما اسمك؟", ""); alert(name); الشيفرة كاملة: <!DOCTYPE html> <html> <body> <script> 'use strict'; let name = prompt("ما اسمك؟", ""); alert(name); </script> </body> </html> ترجمة -وبتصرف- للفصل Interaction: alert, prompt, confirm من كتاب The JavaScript Language اقرأ أيضًا المقال التالي: المعاملات الشرطية المقال السابق: معاملات الموازنة كامل مقالات دليل تعلم جافاسكربت
  3. لا شك أنَّك تعرَّفت مسبقًا على معاملات الموازنة من أحد دروس الرياضيات في المدرسة وهي: أكبر/أصغر من: a < b - a > b. أكبر/أصغر من أو يساوي: a <= b - a >= b. المساواة: a == b (يرجى ملاحظة أنَّ هذا المعامل عبارة عن علامة يساوي مزدوجة =. العلامة المنفردة a = b خاصة بمعامل الإسناد الذي تحدثنا عنه في المقال السابق). عدم المساواة: يُعبر عنه في الرياضيات بالرمز≠، ولكن يُعبِّر عنه برمجيًّا في JavaScript بإشارة يساوي منفردة مع إشارة تعجب قبلها بالشكل: a != b. النتيجة عبارة عن قيمة منطقية مثل كل المعاملات الأخرى، تُرجِع معاملات الموازنة قيمة منطقية دومًا. true - تعني «نعم» أو «صواب» أو «الموازنة مُحقَّقة». false - تعني «لا» أو «خطأ» أو «الموازنة غير مُحقَّقة». إليك أمثلة عن هذه المعاملات: alert( 2 > 1 ); // true (الموازنة صحيحة) alert( 2 == 1 ); // false (الموازنة خطأ) alert( 2 != 1 ); // true (الموازنة صحيحة) يمكن إسناد نتيجة معامل الموازنة لمتغير تمامًا مثل أي قيمة: let result = 5 > 4; // إسناد الناتج من عملية الموازنة لمتغير alert( result ); // true موازنة السلاسل النصية لمعرفة ما إذا كانت السلسلة النصية أكبر من الأخرى، تستخدم JavaScript ما يسمى بترتيب القاموس (dictionary) أو ترتيب المعجم (lexicographical). بمعنى آخر، تتم موازنة السلاسل النصية حرفًا تلو الآخر. على سبيل المثال: alert( 'Z' > 'A' ); // true alert( 'Glow' > 'Glee' ); // true alert( 'Bee' > 'Be' ); // true خوارزمية موازنة سلسلتين نصيتين بسيطة: موازنة الحرف الأول من كلا السلسلتين. إذا كان الحرف الأول من السلسلة النصية الأولى أكبر (أو أقل) من السلسلة النصية الأخرى، حينها تكون الأولى أكبر (أو أقل) من الثانية وبذلك تنتهي عملية الموازنة. لكن إذا كانت الأحرف الأولى في كلا السلسلتين متماثلة، وازن الأحرف الثانية بالطريقة نفسها. كرر حتى نهاية أي سلسلة. إذا انتهت كلا السلسلتين بالطول نفسه، فهما متساويتان. خلاف ذلك يكون السلسلة النصية الأطول هو الأكبر. في الأمثلة أعلاه، تحصل الموازنة 'Z' > 'A' على النتيجة في الخطوة الأولى بينما تُوازن السلسلتين النصيتين "Glow" و "Glee" حرفًا تلو الآخر حتى الحرف الأخير بالتسلسل التالي: G هو نفسه G. l هو نفسه l. o أكبر من e. توقف هنا، السلسلة الأولى أكبر. ليس قاموس حقيقي، ولكنه ترتيب ترميز اليونيكود إنَّ خوارزمية الموازنة المذكورة أعلاه تعادل تقريبًا تلك المستخدمة في القواميس ودفاتر الهاتف، ولكن مع اختلاف بسيط يتعلق بحالة الحرف. فالحرف الكبير "A" لا يساوي الحرف الصغير "a" كما تعتقد فأيهما أكبر برأيك؟ الحرف الصغير "a" طبعًا. أسمعك تسأل لماذا؟ لأنَّ الحرف الصغير له رقم تسلسلي أكبر في جدول الترميز المقابل له في جدول اليونيكود المستخدم في JavaScript، حسنًا، سكفي إلى هنا وسنعاود الحديث عن هذا الموضوع والنتائج المترتبة عليه في فصل السلاسل النصية. موازنة بين أنواع البيانات المختلفة عند موازنة أنواع بيانات مختلفة، تحوّل JavaScript القيم إلى أعداد. على سبيل المثال: alert( '2' > 1 ); // true, تُحوَّل السلسلة النصية '2' إلى العدد 2 alert( '01' == 1 ); // true, تُحوَّل السلسلة النصية '01' إلى العدد 1 بالنسبة للقيم المنطقية، true تصبح 1 و false تصبح 0. على سبيل المثال: alert( true == 1 ); // true alert( false == 0 ); // true نتيجة مضحكة أليس كذلك؟! من الممكن في الوقت نفسه أن تكون القيمتان: متساويتين. واحدة منهما true والأخرى false. إليك مثال عن حالة مماثلة: let a = 0; alert( Boolean(a) ); // false let b = "0"; alert( Boolean(b) ); // true alert(a == b); // true! من وجهة نظر JavaScript، هذه النتيجة طبيعية تمامًا. تُحوّل عملية التحقق من المساواة القيم باستخدام التحويل العددي (وبالتالي السلسلة النصية "0" تساوي القيمة 0)، بينما يستخدم التحويل الصريح Boolean مجموعة أخرى من القواعد. معامل المساواة الصارمة معامل المساواة العادية == لديه مشكلة، وهي عدم قدرته على التمييز بين 0 و false: alert( 0 == false ); // true يحدث الشيء نفسه مع السلسلة النصية الفارغة: alert( '' == false ); // true يحدث هذا لأنَّ الأنواع المختلفة من العاملات تُحول إلى أعداد بواسطة معامل المساواة ==. السلسلة النصية الفارغة مثل false، تصبح صفرًا. ماذا نفعل إذا كنا نرغب في التمييز بين 0 و false؟ معامل المساواة الصارمة === يتحقق من المساواة دون تحويل القيم. بمعنى آخر، إذا كان a وb قيمتين من نوعين مختلفين، فسوف تُرجع المعادلة a === b على الفور false دون محاولة تحويلها، وبذلك يتحقق المعامل === من تساوي النوع أولًا ثم تساوي القيمة. دعنا نجرب: alert( 0 === false ); // false, لأن القيمتين من نوعين مختلفين هناك أيضًا معامل عدم مساواة صارم ‎!==‎ مماثل للمعامل ‎!=‎. يعد معامل المساواة الصارمة أطول قليلاً في الكتابة، ولكنه أكثر وضوحًا ويترك مساحة أقل للأخطاء. الموازنة مع قيمة فارغة null وغير مُعرّفة undefined دعنا نرى المزيد من الحالات الخاصة. تسلك عملية الموازنة سلوكًا غير منطقي عند موازنة قيمة فارغة null أو غير مُعرّفة undefined مع قيم أخرى، إذ هاتان القيمتان من نوعين مختلفين. تذكر أنَّه للتحقق من المساواة بصرامة، استعمل المعامل === دومًا: alert( null === undefined ); // false للتحقق من المساواة دون أخذ النوع بالحسبان، استعمل المعامل ==. بمعنى أنَّ القيمتين null و undefined متساويتان فقط مع بعضهما ولكن ليستا متساويتان مع أي قيمة أخرى. alert( null == undefined ); // true الرياضيات ومعاملات الموازنة الأخرى ‎< > <= >=‎ القيمة الفارغة وغير المُعرّفة null و undefined يتم تحويلها إلى عدد: null تصبح 0، بينما undefined تصبح NaN. الآن دعنا نرى بعض الأشياء المضحكة التي تحدث عندما نطبق هذه القواعد، والأهم من ذلك هو كيفية تجنب هذا الفخ. نتيجة غريبة: null مقابل 0 دعنا نوازن null مع 0: alert( null > 0 ); // (1) false alert( null == 0 ); // (2) false alert( null >= 0 ); // (3) true رياضيًّا، هذا غريب، إذ تشير النتيجة الأخيرة إلى أنَّ «null أكبر من أو تساوي 0»، لذلك يجب في إحدى الموازنات أعلاه أن تكون صحيحة true، لكن كلاهما خطأ. السبب هو أنَّ التحقق من المساواة == ومعاملات الموازنة ‎> < >= <=‎ تعمل بشكل مختلف. تحول الموازنات القيمة الفارغة null إلى عدد، وتعاملها على أنها 0 ولهذا السبب، نتيجة الموازنة في المثال السابق في السطر (3) null >= 0 مُحقَّقة أي true وفي السطر (1) خطأ null > 0. من ناحية أخرى، يتم التحقق من المساواة == على undefinedوnull بدون أي تحويل، حيث أنه يساوي كل منهما الآخر ولا يساويها أي قيمة أخرى. لهذا السبب، نتيجة الموازنة في المثال السابق في السطر (2) null == 0 غير محقَّقة. القيمة غير المُعرّفة undefined غير قابلة للموازنة أي لا ينبغي موازنتها undefined مع القيم الأخرى: alert( undefined > 0 ); // false (1) alert( undefined < 0 ); // false (2) alert( undefined == 0 ); // false (3) لماذا يُكره الصفر كثيرًا؟ دائما خطأ! حصلنا على هذه النتائج لأن: معاملات الموازنة في السطر (1) و(2) في المثال السابق تُرجع false، لأن القيمة undefined تُحوّل إلى NaN وهي عبارة عن قيمة رقمية خاصة تعيد false لكافة الموازنات. تُرجع عملية التحقق من المساواة في السطر(3) القيمة false، لأن القيمة غير المُعرّفة undefined تساوي فقط القيمة null و undefined، ولا تساوي قيم أخرى. تجنب المشاكل لماذا ذكرنا هذه الأمثلة؟ هل يجب أن نتذكر هذه الخصائص في كل وقت؟ نعم، ولا فلا توجد إجابة دقيقة. على أي حال، ستصبح هذه الأشياء التي تراها صعبة ومعقدة تدريجيًا مألوفة وبديهية، ومع ذلك هناك طريقة جيدة للتهرب من مثل هذه الأمثلة: تعامل بالصورة المألوفة مع أي موازنة بها undefined/null، باستثناء المساواة الصارمة === فهي تحتاج معاملة استثنائية. لا تستخدم معاملات الموازنة ‎>= > < <=‎ مع متغير قد يأخذ إحدى القيمتين null/undefined، إلا إذا كنت متأكدًا حقًا مما تفعله. إذا كان المتغير عبارة عن هاتين القيمتين، فتحقق منها بشكل منفصل. الخلاصة تُرجع معاملات الموازنة قيمة منطقية. تُوازن السلاسل النصية حرفًا تلو الآخر حسب ترتيب القاموس (dictionary). عند موازنة قيم من أنواع بيانات مختلفة، يتم تحويلها إلى أرقام (باستثناء التحقق من المساواة الصارمة). القيم الفارغة null وغير المعرّفة undefined تساوي == بعضها بعضًا، ولا تساوي أي قيمة أخرى. كن حذرًا عند استخدام معاملات موازنة مثل> أو < مع متغيرات يمكن أن تكون فارغة null أو غير معرّفة undefined ويفضل التحقق من ذلك بشكل منفصل. .task__importance { color: #999; margin-left: 30px; } .task__answer { border: 3px solid #f7f6ea; margin: 20px 0 14px; position: relative; display: block; padding: 25px 30px; } code { background-color: rgb(250, 250, 250); border-radius: 3px; } تمارين الموازنات الأهمية: 5 ماذا ستكون نتيجة هذه الموازنات 5 > 4 "apple" > "pineapple" "2" > "12" undefined == null undefined === null null == "\n0\n" null === +"\n0\n" الحل 5 > 4 ← true "apple" > "pineapple"‏ ← false "2" > "12" ← true undefined == null‏ ← true undefined === null‏ ← false null == "\n0\n"‏ ← false null === +"\n0\n"‏ ← false بعض الأسباب: نتيجة الموازنة واضحة، صحيحة. حسب موازنة القاموس، النتيجة خاطئة. حسب موازنة القاموس مرة أُخرى، الحرف الأول من القيمة"2" أكبر من الحرف الأول من القيمة"1". القيم null و undefined تساويان بعضهما فقط. المساواة الصارمة صارمة فيما يخص نوع المتغير، وعند اختلاف نوع طرفي المعامل فإن النتيجة تصبح خاطئة. انظر للنقطة رقم (4). مساواة صارمة لنوعان مختلفان من القيم. ترجمة -وبتصرف- للفصل comparisons من كتاب The JavaScript Language اقرأ أيضًا المقال التالي: الدوال التفاعلية: alert ،prompt ،confirm المقال السابق: المعاملات في JavaScript كامل مقالات دليل تعلم جافاسكربت
  4. تعرَّفنا على العديد من المعاملات الحسابية في المدرسة، مثل الجمع +، الضرب *، الطرح – وما إلى ذلك. في هذا المقال، سنشرح معاملات أخرى لم نتعرف عليها في المدرسة بالإضافة إلى تلك المعاملات. مصطلحات جديدة: أحادي، ثنائي، عامل قبل أن نمضي قدمًا في هذا المقال، دعنا نتعرَّف على بعض المصطلحات الجديدة. العوامل (operands): هي العناصر (القيمة) التي تُنفَّذ عملية المعاملات (operators) عليها. على سبيل المثال، في عملية الضرب 5 * 2، يوجد عاملان؛ العامل الأيسر هو 2 والأيمن هو 5. يطلق عليها البعض أحيانًا الاسم «وسائط» (arguments) بدلًا من «عوامل» (operands). المعامل الأحادي: يكون المعامل أحاديًّا (unary) إذا كان لديه عامل (operand) واحد فقط. على سبيل المثال، عملية النفي هي عملية أحادية، إذ تعكس اشارة العدد، فيصبح سالبًا - إذا كان موجبًا + والعكس صحيح: let x = 1; x = -x; alert( x ); // -1, تم تطبيق النفي الأحادي المعامل الثنائي: يكون المعامل ثنائيًّا (binary) إذا كان لديه عاملان (operands). يوضح المثال التالي إشارة السالب التي في المثال السابق عندما تكون في المعامل الثنائي: let x = 1, y = 3; alert( y - x ); // 2, معامل الطرح الثنائي يطرح القيم تقنيًّا، نتحدث هنا عن نوعين من المعاملات لإشارة واحدة - هما: النفي الأحادي (العامل الفردي: عكس الإشارة) والطرح الثنائي (عاملان: عملية طرح)، لذا يجب التفريق بينهما. وصل سلاسل نصية عبر المعامل + الآن، سنتعرَّف على ميِّزات خاصة بمعاملات JavaScript تتجاوز تلك التي تعلمناها في المدرسة. المتعارف عليه أنَّ معامل الجمع + يجمع الأرقام. لكن إذا تم تطبيق معامل الجمع + على سلاسل نصية، فإنه يُوصل هذه السلاسل النصية مع بعضها بعضًا ويضعها في سلسلة نصية واحدة. let s = "my" + "string"; alert(s); // mystring لاحظ أنه يتم تحويل العدد إلى سلسلة نصية عن طريق وضعه داخل علامات الاقتباس ("") ويعامل آنذاك معاملة السلسلة النصية. ولاحظ أيضًا إذا كان أحد العاملين (operands) عبارة عن سلسلة نصية، فسيُحوَّل الآخر تلقائيًا إلى سلسلة نصية. إليك المثال التالي: alert( '1' + 2 ); // "12" alert( 2 + '1' ); // "21" كما رأيت، لا يهم ما إذا كان العامل الأول عبارة عن سلسلة نصية أم الثاني. القاعدة بسيطة: إذا كان أحد العاملين عبارة عن سلسلة نصية، فسيُحوَّل الآخر إلى سلسلة نصية أيضًا. لكن انتبه! المعاملات تبدأ من اليسار إلى اليمين. فإذا كان هناك عددان متبوعان بسلسلة نصية، فستُجمَع الأعداد قبل تحويلها إلى سلسلة نصية: alert(2 + 2 + '1' ); // "أي أن الناتج "41" وليس "221 خاصية وصل السلاسل النصية وجمعها في سلسلة واحدة (String concatenation) ميزة خاصة بمعامل الجمع +، بينما تعمل المعاملات الحسابية الأخرى مع الأعداد فقط. فعلى سبيل المثال، الطرح والقسمة: alert( 2 - '1' ); // 1 alert( '6' / '2' ); // 3 خاصية التحويل العددي يوجد لمعامل الجمع + صيغتان: الأول معامل الجمع الثنائي كما في خاصية دمج السلاسل النصية، والثاني معامل الجمع الأحادي كما في هذه الخاصية. معامل الجمع الأحادي أو بمعنى آخر، معامل الجمع + المطبق على قيمة واحدة، لا يُحدث تغييرًا على الأعداد. ولكن إذا لم يكن العامل عددًا، فإن عملية الجمع الأحادي تحوّله إلى عدد. اطلع على المثال التالي: // لا تأثير على الأعداد let x = 1; alert( +x ); // 1 let y = -2; alert( +y ); // -2 // تحويل غير الأعداد alert( +true ); // 1 alert( +"" ); // 0 يقوم هذا المعامل هنا مقام الدالة Number‎، لكنه أقصر وأبسط. تنشأ الحاجة لتحويل السلاسل النصية إلى أعداد في كثير من الأحيان. على سبيل المثال، إذا كنا نحصل على القيم من قالب HTML، فهي غالبًا ما تكون عبارة عن سلاسل نصية. ماذا لو أردنا دمجها؟ معامل الجمع الثنائي سيضيفها كسلاسل نصية: let apples = "2"; let oranges = "3"; alert( apples + oranges ); // "23", معامل الجمع الثنائي يدمج السلاسل النصية إذا كنا نريد أن نعاملها كأعداد، نحتاج إلى تحويلها ثم دمجها: let apples = "2"; let oranges = "3"; // كلا القيمتين حُولتا إلى أعداد قبل تطبيق معامل الجمع الثنائي alert( +apples + +oranges ); // 5 // بصيغة أطول // alert( Number(apples) + Number(oranges) ); // 5 من وجهة نظر عالم رياضيات، تبدو كثرة معاملات الجمع غريبة. ولكن من وجهة نظر المبرمج، لا يوجد شيء مميز: يتم تطبيق معاملات الجمع الأحادي أولاً لتحويل السلسلة النصية إلى عدد، ثم يجمع معامل الجمع الثنائي العددين الناتجين. لماذا يتم تطبيق معاملات الجمع الأحادية على القيم قبل الثنائية؟ هذا يعود للأولوية الأعلى في التنفيذ كما سنرى بعد قليل. ترتيب أولوية المعاملات إذا كان في المعادلة أكثر من معامل واحد، يتم تحديد ترتيب التنفيذ حسب أولوية هذه المعاملات. في المدرسة، تعلمنا جميعًا أنه يجب حساب الضرب في المعادلة1 + 2 * 2 قبل الجمع، هذا تحديدًا ما يسمى أولوية العملية الرياضية. أي أن عملية الضرب لها أولوية أعلى من الجمع. تتخطى الأقواس أولوية أي معامل، لذلك إذا لم نكن راضين عن أولوية المعاملات (operations) في المعادلة، يمكننا استخدام الأقواس لتغييرها. على سبيل المثال: (1 + 2) * 2. هناك العديد من المعاملات في JavaScript. كل معامل لديه رقم في ترتيب الأولوية، والمعامل صاحب الأولوية الأعلى يُنفَّذ أولًا. إذا كانت الأولوية لمجموعة معاملات في نفس الترتيب، يكون التنفيذ من اليسار إلى اليمين. إليك مقتطف من جدول الأولوية (لست بحاجة إلى حفظ ذلك، لكن لاحظ أن المعاملات الأحادية أعلى أولوية من المعاملات الثنائية المقابلة). الأولوية اسم المعامل إشارة المعامل ... ... ... 16 الجمع الأحادي + 16 النفي الأحادي - 14 الضرب * 14 القسمة / 13 الجمع الثنائي + 13 الطرح الثنائي - ... ... ... 3 الإسناد = ... ... ... كما ترى، معامل الجمع الأحادي له الأولوية 16 وهي أعلى من 13 لمعامل الجمع الثنائي. لهذا السبب، يُنفَّذ معامل الجمع الأحادي أولًا في المعادلة +apples + +oranges الذي يمثِّل عملية التحويل قبل عملية الجمع وهذا هو المطلوب. معامل الإسناد = لاحظ أنَّ معامل الإسناد = مدرجٌ في جدول الأولوية الخاص بالمعاملات مع أولوية منخفضة للغاية وهي 3. لهذا السبب، عندما نسند قيمة لمتغير، مثل x = 2 * 2 + 1، تُنفَّذ العمليات الحسابية حسب أولويتها ثمَّ تُسنَد القيمة الناتجة (5) إلى المتغيِّر x وتُخزَّن فيه. let x = 2 * 2 + 1; alert( x ); // 5 من الممكن سَلسَلة معاملات الإسناد: let a, b, c; a = b = c = 2 + 2; alert( a ); // 4 alert( b ); // 4 alert( c ); // 4 يتم تنفيذ سَلسَلة معاملات الإسناد من اليمين إلى اليسار. أولاً، يُقيَّم التعبير 2 + 2 الموجود في أقصى اليمين ثم تُسنَد القيمة الناتجة عنه إلى المتغيرات الموجودة على اليسار:c، وb و a. في النهاية، تشترك جميع تلك المتغيرات في القيمة النهائية الناتجة. معامل الإسناد = يُرجع قيمة المعامل دائما يرجع قيمة. هذا واضح في معامل الجمع + أو الضرب *، ويتبع معامل الإسناد = أيضًا هذه القاعدة. فالاستدعاء x = Value يُخزِّن القيمة في x ثم يرجعها. يوضح المثال التالي كيفية الاستفادة من هذه الميزة باستخدام القيمة الناتجة عن عملية الإسناد في معادلة أخرى أكثر تعقيدًا، وبذلك نضرب عصفورين بحجر واحد: let a = 1; let b = 2; let c = 3 - (a = b + 1); alert( a ); // 3 alert( c ); // 0 في المثال أعلاه، تكون نتيجة a = b + 1 هي القيمة التي جرى إسنادها إلىa أي 3، ثم يتم طرح من هذه القيمة 3. شيفرة مضحكة، أليس كذلك؟! لكن يجب أن نفهم كيف تعمل لأنه في بعض الأحيان نراها في مكتبات خارجية كتبها آخرون، ولا يُفضل إطلاقًا أن نكتب مثل هذه الشيفرات، لأنَّ هذه الحيل لا تجعل من الشيفرة أكثر وضوحًا أو أكثر قابلية للقراءة. معامل باقي القسمة % معامل باقي القسمة %، لا يرتبط بالنسب المئوية. الناتج من هذه المعادلة a % b هو العدد المتبقي من قسمة العدد الصحيح a على العدد الصحيحb. إليك مثال عنه: alert( 5 % 2 ); // 1 (هو الباقي من قسمة 5 على 2) alert( 8 % 3 ); // 2 (هو الباقي من قسمة 8 على 3) alert( 6 % 3 ); // 0 (هو الباقي من قسمة 6 على 3) معامل القوة ** معامل القوة ** هو إضافة حديثة لـ JavaScript. ليكن لدينا الرقم الطبيعي b، فيكون ناتج العملية a ** b هو الرقم a مضروبًا في نفسه عدد b من المرات: alert( 2 ** 2 ); // 4 (2 * 2) alert( 2 ** 3 ); // 8 (2 * 2 * 2) alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2) يعمل معامل القوة مع الأعداد غير الصحيحة أيضًا مثل: alert( 4 ** (1/2) ); // 2 (معامل القوة ½ هو نفس الجذر التربيعي) alert( 8 ** (1/3) ); // 2 (معامل القوة ⅓ هو نفس الجذر التكعيبي) معاملات الزيادة ++ والنقصان -- تُعدُّ الزيادة على العدد أو إنقاصه بمقدار 1 من أكثر العمليات العددية شيوعًا. لذلك، هناك معاملات خاصة لهذا الغرض: معامل الزيادة ++ يزيد على قيمة المتغير مقدار 1: let counter = 2; counter++; // ببساطة counter = counter + 1 هو اختصار للعملية alert( counter ); // 3 معامل النقصان -- ينقص من قيمة المتغير مقدار 1: let counter = 2; counter--; // counter = counter - 1 هو اختصار للعملية alert( counter ); // 1 تنبيه: معاملات الزيادة / النقصان خاصة بالمتغيرات فقط، ومحاولة تطبيقها على قيم عددية مثل ‎5++‎ سيعطي خطأ. يمكن وضع هذين المعاملين ++، -- قبل المتغير أو بعده. عندما يتبع المعامل المتغير، هذا ما يسمى «النموذج اللاحق» (postfix form) مثل counter++. وبالمثل، «النموذج السابق» (prefix form)، عندما يأتي المعامل قبل المتغير مثل ++counter. كلا النموذجين يقومان بالعمل نفسه وهو الزيادة على قيمة المتغير counter بمقدار 1. إذن، هل هناك فرق؟ نعم، ولكن لا يمكننا رؤيته إلا إذا استخدمنا القيمة المعادة من العملية تلك. دعني أوضح لك أكثر. كما نعلم، جميع المعاملات ترجع قيمة وكذلك أيضًا معاملات الزيادة/النقصان. يعيد النموذج السابق القيمة الجديدة بينما يعيد النموذج اللاحق القيمة القديمة (قبل الزيادة / النقصان). إليك مثال على ذلك ليتضح كل الفرق وضوح الشمس: let counter = 1; let a = ++counter; // (*) alert(a); // 2 في السطر المُميّز بالنجمة (*)، يزيد النموذج السابق ++counter قيمة المتغير counter ويعيد القيمة الجديدة الناتجة وهي 2. لذا، تُظهر الدالة alert القيمة 2. الآن، دعني استخدم النموذج اللاحق بدلًا من النموذج السابق لمعرفة الفرق: let counter = 1; let a = counter++; // (*) alert(a); // 1 في السطر المُميّز بالنجمة (*)، يزيد النموذج اللاحق counter++ قيمة المتغير counter لكنه يعيد القيمة القديمة (قبل الزيادة). لذا، تُظهِر الدالة alert القيمة 1. مختصر القول: إذا لم يتم استخدام القيمة الناتجة من معاملي الزيادة والانقاص، فلا يوجد فرق في النموذج الذي يتم استخدامه سواءً سابق أو لاحق: let counter = 0; counter++; ++counter; alert( counter ); // 2, كلا السطرين يؤديان نفس الغرض أمَّا إذا كنت ترغب في زيادة قيمة المتغير واستخدامها مباشرةً، فأنت بحاجة إلى استعمال النموذج السابق: let counter = 0; alert( ++counter ); // 1 وإذا كنت ترغب في زيادة قيمة المتغير ولكنك تريد استخدام قيمته السابقة، فاستعمل النموذج اللاحق: let counter = 0; alert( counter++ ); // 0 معاملات زيادة / نقصان داخل معاملات اخرى: يمكن استخدام معاملات زيادة / نقصان (++ / --) داخل المعادلات أيضًا، وأولويتها في التنفيذ أعلى من معظم المعاملات الحسابية الأخرى. إليك المثال التالي: let counter = 1; alert( 2 * ++counter ); // 4 وازنه مع المثال التالي: let counter = 1; alert( 2 * counter++ ); // 2, لأن counter++ يرجع القيمة القديمة رغم أنَّه مقبول من الناحية التقنية، إلا أنَّ هذه الشيفرة عادة ما تجعل الشيفرة الكلية صعبة القراءة. اتباع نموذج «سطر واحد يفعل أشياء متعددة» ليس جيدًا ويولد شيفرة صعبة القراءة والتنقيح. أثناء تَصفُّح الشيفرة سريعًا يمكن أن لا تنتبه على شيء مثل counter++، أي لن تلاحظ أنَّ قيمة المتغير قد زادت. فتخيل ما سيحصل إن حدث خطأ ما مع وجود مئات مثل تلك الأسطر التي تنجز عدة أشياء سويةً! أنصحك باستخدام أسلوب «سطر واحد - إجراء واحد» (one line – one action): let counter = 1; alert( 2 * counter ); counter++; المعاملات الثنائية تتعامل المعاملات الثنائية (Bitwise operators) مع العوامل كأعداد صحيحة بحجم 32 بت وتعمل على مستوى تمثيلها الثنائي (binary representation). هذه العوامل ليست خاصة بـ JavaScript، وهي مدعومة في معظم لغات البرمجة. إليك قائمة بالمعاملات الثنائية (Bitwise operators): المعامل AND (&) المعامل OR (|) المعامل XOR (^) المعامل NOT (~) معامل الإزاحة نحو اليسار LEFT SHIFT (>>) معامل الإزاحة نحو اليمين RIGHT SHIFT (<<) معامل الإزاحة نحو اليمين مع إدخال أصفار ZERO-FILL RIGHT SHIFT (<<<) نادرًا ما تحتاج إلى استخدام مثل هذه المعاملات. وتحتاج لفهمها إلى الخوض في التمثيل الثنائي للأعداد (الصيغة الثنائية المقابلة للصيغة العشرية المفهومة للبشر) وليس من الجيد القيام بذلك الآن، خاصة أننا لسنا بحاجة إلى ذلك في هذا الوقت. إذا كنت فضولي يمكنك قراءة توثيق المعاملات الثنائية في JavaScript في موسوعة حسوب، وهذا كافيًّا الآن. وسنشرحها عمليًّا عندما تنشأ حاجة حقيقية لها في مراحل متقدمة. معاملات التعديل المباشر على المتغير (Modify-in-place) غالبًا ما نحتاج إلى تطبيق معامل على متغير ما وتخزين القيمة الجديدة في المتغير نفسه. انظر مثلًا إلى المثال التالي: let n = 2; n = n + 5; n = n * 2; يمكن اختصار الشيفرة السابقة باستخدام ‎+=‎ و ‎*=‎: let n = 2; n += 5; // (n = n + 5 وهذا يماثل) n = 7 أي تصبح n *= 2; // (n = n * 2 وهذا يماثل) n = 14 تصبح الآن alert( n ); // 14 معاملات التعديل والإسناد (modify-and-assign) متاحة لجميع المعاملات الحسابية والثنائية مثل: ‎/=‎ و ‎-=‎ وتملك هذه المعاملات الأولوية نفسها التي لدى معامل الإسناد العادي =، لذا فهي تُنفَّذ بعد معظم المعاملات الأخرى: let n = 2; n *= 3 + 5; alert( n ); // 16 (n *= 8 القسم الأيمن يُقيَّم أولًا وهذا يماثل) معامل الفاصلة , معامل فاصلة (Comma) , هو واحد من أندر المعاملات وأكثرها غرابة. في بعض الأحيان يتم استخدامه لكتابة شيفرة أقصر، لذلك نحن بحاجة إلى التعرف عليه لفهم ذلك. يتيح لنا معامل الفاصلة تقييم العديد من المعادلات عند فصلها بفاصلة ,. يجري تقييم كل قسم منها ولكن يتم إرجاع نتيجة آخر واحد فقط. تفحَّص المثال التالي: let a = (1 + 2, 3 + 4); alert( a ); // 7 (الناتج من جمع 3+4) هنا، يُقيَّم القسم الأول من المعادلة 1+2 ويُتجاهَل قيمته ثم بعد ذلك يُقيَّم القسم الثاني 3+4 وتعاد قيمته كنتيجة نهائية. معامل الفاصلة له أولوية منخفضة جدًا يرجى ملاحظة أن معامل الفاصلة له أولوية منخفضة للغاية، أقل من معامل الإسناد =، لذلك الأقواس مهمة في المثال أعلاه. بدون الأقواس: a = 1 + 2 ، 3 + 4 يُنفَّذ معامل الجمع + أولاً، فتصبح المعادلة a= 3,7، ثم يُنفَّذ معامل الإسناد = فتصبح a=3، وأخيرًا لا يُطبَّق أي معامل على العدد الموجود بعد الفاصلة، أي يُتجاهَل العدد7. لماذا نحتاج إلى معامل يتجاهل كل القيم باستثناء قيمة الجزء الأخير؟ في بعض الأحيان، يستخدمه المبرمجون في بنيات أكثر تعقيدًا لوضع العديد من الإجراءات في سطر واحد. قد تكون أبسط تلك البنيات المعقدة هي بنية الحلقية التكرارية التالية: // ثلاث معاملات في سطر واحد for (a = 1, b = 3, c = a * b; a < 10; a++) { ... } تُستخدَم هذه الحيل في العديد من أطر JavaScript. لكنها في العادة لا تحسّن قابلية القراءة للشيفرة، لذلك يجب عليك التفكير جيدًا قبل استخدامها. .task__importance { color: #999; margin-left: 30px; } .task__answer { border: 3px solid #f7f6ea; margin: 20px 0 14px; position: relative; display: block; padding: 25px 30px; } table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } code { background-color: rgb(250, 250, 250); border-radius: 3px; } تمارين النموذج السابق والنموذج اللاحق الأهمية: 5 ما هي القيم النهائية للمتغيرات a ،b ،c ،d بعد تنفيذ الشيفرة التالية؟ let a = 1, b = 1; let c = ++a; // ? let d = b++; // ? الحل: الإجابة هي: a = 2 b = 2 c = 2 d = 1 let a = 1, b = 1; alert( ++a ); // 2, النموذج السابق يُرجع القيمة الجديدة alert( b++ ); // 1, النموذج اللاحق يُرجع القيمة القديمة alert( a ); // 2, تتم الزيادة مرة واحدة alert( b ); // 2, تتم الزيادة مرة واحدة نتيجة عملية الإسناد الأهمية: 3 ما هي قيم المتغيرين a و x بعد تنفيذ الشيفرة التالية؟ let a = 2; let x = 1 + (a *= 2); الحل الإجابة هي: a = 4 (مضروبًا في العدد 2) x = 5 (عبارة عن مجموع العدد 1 والعدد 4) ترجمة -وبتصرف- للفصل operators من كتاب The JavaScript Language انظر أيضًا المقال التالي: معاملات الموازنة المقال السابق: التحويل بين الأنواع كامل مقالات دليل تعلم جافاسكربت
  5. هذا المقال تمت كتابته بتعاون بين Joe Richardson و Robin Rendle ومجموعة من فريق موقع CSS-Tricks. أراد Joe إضافة مقال بخصوص BEM التي أحببناها وكان لدى كل منا أفكارًا وآراءً حولها، لذلك قررنا أن نتعاون سويًا لكتابة هذا المقال. تُعدُّ منهجية BEM (وهي اختصار لهذه الكلمات معًا Block و Element و Modifier) مصطلح تسمية شائع يستخدم من أجل الأصناف في HTML و CSS تم تطويره بواسطة فريق في Yandex؛ هدفها هو مساعدة المطورين في فهم العلاقة بين HTML و CSS في مشروع معين بشكل أفضل. فيما يلي مثال حول ما يكتبه مطور CSS في نمط BEM: /* مكون كتلة */ .btn {} /* عنصر يعتمد على كتلة */ .btn__price {} /* مُعدِّل يعدِّل تنسيق الكتلة */ .btn--orange {} .btn--big {} في شيفرة CSS السابقة، الكتلة (Block) عبارة عن عنصر جديد في أعلى مستوى من التجريد (top-level abstraction) على سبيل المثال زر: ‎.btn{}‎. يجب اعتبار الجملة البرمجية هذه بمثابة أحد الأبوين، إذ يمكن وضع العناصر الأبناء (elements) في الداخل ويتم الإشارة إليها بواسطة شرطتين سفليتين يتبع اسم الكتلة أو الحاوية البرمجية تلك مثل ‎.btn__price{}‎. أخيرًا، يمكن للمُعدلات (modifiers) معالجة الحاوية البرمجية (Block) بحيث يمكننا تمييز أو تصميم ذلك المكون المحدد دون إحداث تغييرات على بقية الحاويات البرمجية الأخرى يتم ذلك عن طريق إلحاق شرطتين باسم الحاوية البرمجية Block تمامًا مثل btn--orange. تبدو الشيفرة كما في المثال التالي: <a class="btn btn--big btn--orange" href="http://css-tricks.com"> <span class="btn__price">$9.99</span> <span class="btn__text">Subscribe</span> </a> لو كتب مطور آخر هذه الشيفرة ولم يكن لدينا خبرة في CSS، فيجب أن نأخذ فكرة جيدة عن أي الأصناف ومسؤوليتها وكيف تعتمد على بعضها بعضًا. يستطيع المطورون آنذاك بناء مكوناتهم الخاصة وتعديل الحاويات (الكتل) الموجودة إلى المحتوى الذي يريدونه. يحتمل بدون كتاب مثل شيفرة CSS هذه أن يتمكن المطورون من كتابة عدة مجموعات مختلفة من الأزرار ببساطة عبر تعيير صنف في الشيفرة: في البداية، قد تبدو هذه الصياغة أبطأ من بناء صنف جديد لكل نوع من أنواع الأزرار، ولكن هذا غير صحيح لعدة أسباب سنذكرها. لماذا علينا أخذ BEM في الحسبان؟ إذا كنا نريد إنشاء تصميم جديد لعنصر معين، يمكننا أولًا النظر في الحاويات البرمجية لمعرفة أي المُعدِّلات، والعناصرالفرعية موجودة بالفعل. ربما ندرك أننا لسنا بحاجة لكتابة أي تعبير CSS برمجي آخر لأن هناك معدّل موجود مسبقًا يفي بالغرض. إذا كنا نقرأ الوسوم بدلاً من تعابير CSS البرمجية، يجب أن نكون قادرين على الحصول بسرعة على فكرة حول العنصر الذي يعتمد على عنصر آخر؛ في المثال السابق، يمكننا رؤية أن العنصر ‎.btn__price يعتمد على العنصر ‎.btn، حتى لو لم نكن على دراية بعمل أي من تلك العناصر. يمكن للمصممين والمطورين تسمية العناصر لتسهيل الاتصال بين فريق المطورين بمعنى آخر، يوفر BEM لكل مطور في المشروع تسمية صيغة إعلانية للعناصر يمكنه مشاركتها بحيث تكون في نفس الصفحة. حدد Harry Roberts فائدة رئيسية أخرى لاستخدام صيغة برمجية مثل BEM حين كتب التالي عن تحسين ثقة المطور: "هذا هو السبب الرئيسي الذي يجعلنا ننتهي من قواعد الشفرة المتضخمة المليئة بشيفرات برمجية قديمة وغير قابلة للتعديل من CSS. نحن نفتقر إلى الثقة في أن نكون قادرين على العمل مع الأنماط الحالية وتعديلها لأننا نخشى عواقب أن تعمل CSS عالميًا، إذ هي مشهورة بحد ذاتها. تتلخص كل المشكلات تقريبًا المتعلقة بـ CSS على نطاق واسع في الثقة (أو عدم وجودها)، لذلك لا يقومون بإجراء تغييرات لأنهم لا يعرفون ما هي الآثار لهذه التغييرات على المدى البعيد." وبالمثل، يناقش Philip Walton حل لهذه المشكلة وهو إلتزام عدد كاف من المطورين بمبادئ BEM: "على الرغم من أن الشيفرة القابلة للتنبؤ بنسبة 100٪ غير متوافرة، من المهم فهم المفاضلات التي تجريها مع الطريقة المتبعة في كتابة التعابير البرمجية التي تختارها. إذا كنت تتبع طريقة BEM الصارمة، فستكون قادرًا على تحديث تعابير CSS وإضافة الشيفرات البرمجية الخاصة بك إليها في المستقبل بثقة تامة بأن هذه التغيرات لن يكون لها أي آثار جانبية." لذلك، إذا كان بإمكان المطورين العمل في مشروع بطريقة أكثر ثقة، فإنهم على يقين من اتخاذ قرارات أكثر ذكاءً حول كيفية استخدام هذه العناصر المرئية. قد لا تكون هذه الطريقة حلًا مثاليًا لجميع هذه المشاكل، لكنها بالتأكيد تمنح المطورين معيارًا لكتابة جمل برمجية أفضل وأكثر قابلية للصيانة في المستقبل. هناك جانب آخر جيد في منهجية BEM، وهو أن كل مجموعة جمل برمجية خاصة بعنصر معين توجد داخل حاوية خاصة به ولا يوجد شيء متداخل مما يجعل خصوصية CSS سلسة جدًا ومنخفضة وهذا هو المطلوب. أي أنك لن تجهد نفسك فيما يتعلق بخصوصية تعابير CSS البرمجية. دعونا نلقي نظرة على بعض المشاكل مع BEM. مشاكل مع BEM‏ CSS لن يقوم أحد بمعاقبتك بالطبع إذا خرجت عن قواعد BEM. لا يزال بإمكانك كتابة محدد CSS كالتالي: .nav .nav__listItem .btn--orange { background-color: green; } يبدو أن المثال السابق يحتوي أجزاء من منهجية BEM، لكنه ليس كذلك فهو يحتوي على محددات متداخلة، ولا يصف المُعدِّل (modifier) بدقة ما يحصل في هذه الجمل البرمجية. إذا فعلنا ذلك، فسنكون فشلنا في تحقيق مبدأ الخصوصية وهذا مفيد جدا لمنهجية BEM. يجب ألا تَبطل كتلةٌ (مثل ‎.nav) عمل كتلة أخرى أو معدل آخر (مثل ‎.btn --orange) وإلا فإن هذا سيجعل من المستحيل تقريبًا قراءة ملف HTML وفهم عمل هذا العنصر. في هذه العملية، نحن ملزمون الى حد كبير أن نكون أهلًا لثقة مطور آخر في البرنامج، هذا ينطبق على HTML أيضًا. ماذا تتوقع إذا رأيت الشيفرة التالية؟ <a class="btn" href="http://css-tricks.com"> <div class="nav__listItem">Item one</div> <div class="nav__listItem">Item two</div> </a> ربما ما يحدث في المثال السابق، هو أن عنصرًا في الحاوية البرمجية block يشتمل على الشيفرة التي يحتاجها المطور، لكن العناصر الأبناء لا تحتاج إلى الصنف ‎.nav على أنه عنصر أب. هذه المشكلة تجعل البرنامج استثنائيًّا وغير متسق ومتناقض مع نفسه وينبغي تجنبها بأي ثمن. لذلك، يمكننا تلخيص هذه المشكلات في: عدم استخدام المُعدلات في الحاويات البرمجية block غير المترابطة. تجنب صنع عناصر رئيسية غير ضرورية عندما يكون العنصر الفرعي موجودًا بشكل جيد بدون أي مشاكل. المزيد من الأمثلة العملية على BEM قائمة قابلة للطي: في هذا المثال، هناك حاوية برمجية block واحدة وعنصران ومُعدِّل واحد. يمكننا هنا إنشاء مُعدِّل مثل ‎.accordion__copy-open يتيح لنا معرفة أنه يجب ألا نستخدمه في حاوية برمجية block أو عنصر آخر. قائمة تنقل: يحتوي هذا المثال على كتلة block واحدة و 6 عناصر ومُعدِّل واحد. من الجيد تمامًا إنشاء حاويات برمجية blocks بدون معدلات على الإطلاق. يمكن للمطور في مرحلة ما في المستقبل أن يربط هذه الحاوية بمعدلات جديدة طالما بقيت ثابتة. عيوب BEM ربما لا تحب استخدام شرطة مزدوجة. حسنًا، استخدم شيئًا آخر فريدًا تستخدمه باستمرار. هنا رأي آخر: هذه الثلاثة محددات الأخيرة جميعها لها مستويات خصوصية مختلفة. تحتمل أن يكون لها عنصر رئيسي أو لا بدون أي قواعد معمول بها، هل من الممكن أن يكون هذا المثال الصغير جيد بالنسبة لك؟ ربما. ولكن كلما زاد عدد تعابير CSS البرمجية في المشروع، زاد عدد الأشياء الصغيرة مثل هذه، وبالتالي زادت مشاكل الخصوصية والتعقيد. ليس بالضرورة اختيار رأي صموئيل هنا، ولكن آراءه شاركها الكثير من الناس لذلك فهو مثال جيد. بخصوص من يرفضون BEM تمامًا فلا بأس بذلك، لكنني أعتقد أنه سيكون من الصعب القول بأن وجود مجموعة من القواعد التي تساعد في الفهم والحفاظ على CSS قابل للتعديل هو فكرة سيئة. في منهجية SMACSS، من المحتمل أن تجد اسم صنف CSS متكون من ثلاثة أحرف. تتبع المُعدِّلات بعدئذٍ اسم الوحدة النمطية باستخدام شرطة: /* مثال عن وحدة */ .btn { } /* btn معدِّل الصنف */ .btn-primary { } /* مع حالة Btn الوحدة */ .btn.is-collapsed { } هذه مجرد طريقة تسمية مختلفة لنفس المشكلة. إنه مشابه إلى حد ما، لكن تكون أكثر تحديدًا بشأن التبعيات والحفاظ على خصوصية التفاصيل. في OOCSS، الحاويات البرمجية هي عامة بالغالب. /* مثال عن وحدة */ .mod { } /* جزء من الوحدة */ .inner { } /* Talk الوحدة */ .talk { } /* تغيير جزء داخل الوحدة */ .talk .inner { } لذلك، يمكنك استخدام أصناف متعددة في HTML للحالات المختلفة. لم يتم تسمية الجزء الداخلي مثل التابع له، لذلك فهو أقل وضوحًا ولكنه قابل لإعادة استخدامه. ستقوم BEM بعمل ‎.mod__inner و ‎.mod--talk و mod-talk__inner.. هذه مجرد اختلافات في المنهجية. تذكر أن لا أحد يجبرك على استخدامها، فهذه قواعد مفروضة ذاتيًا حيث تأتي القيمة من متابعتها. BEM و Sass لأولئك الذين يستخدمون Sass ويستمتعون بتشعيب (nesting) العناصر كوسيلة لتحديد النطاقات لتنسيقات، لازال بإمكانك أن تكون المسؤول عن الصيغة المتشعبة ولكن يمكنك الحصول على CSS غير متشعب، باستخدام ‎@at-root: ملف Scss: .block { @at-root #{&}__element { } @at-root #{&}--modifier { } } يولد ملف CSS التالي: .block { } .block__element { } .block--modifier { } ويمكنك الحصول على ملخص كما تريد! تحقق من منشئ BEM الذي يخص Danield Guillan أو Anders Schmidt Hansen من أجل BEM التعبيرية. الخلاصة أعتقد أنه من الإنصاف القول إنه على الرغم من أن BEM لن يحل جميع مشاكلنا، إلا أنه مفيد بشكل كبير في بناء واجهات قابلة للتطوير والصيانة حيث يجب أن يكون لدى كل فرد في الفريق فكرة واضحة عن كيفية تطوير تلك الأشياء. ذلك لأن الكثير من التطوير في الواجهة الأمامية لا يتعلق فقط بالخدع اللطيفة التي تحل مشكلة صغيرة واحدة على المدى القصير؛ نحتاج إلى اتفاقات وعقود ملزمة بين المطورين بحيث يمكن لبرنامجنا التكيف مع مرور الوقت وعلى المدى البعيد. بشكل عام، أود أن أفكر في BEM كإجابة على سؤال نيكولاس غالاغر: ترجمة -وبتصرف- للمقال BEM 101 لصاحبها Robin Rendle.
  6. المرة الأولى التي صنعت فيها صورة متجاوبة (responsive)، كانت بسيطة مثل ترميز هذه الأسطر الأربعة. img { max-width: 100%; height auto; /* default */ } رغم أن ذلك كان مناسبًا لي كمطور، إلا أنه لم يكن الأفضل للمستخدمين. ماذا يحدث إذا كانت الصورة في الخاصية src ثقيلة؟ على الأجهزة المتطورة (مثل الجهاز الذي يحتوي على ذاكرة وصول عشوائي بسعة 16 جيجابايت)، قد تحدث مشكلة بسيطة في الأداء أو لا تحدث، ولكن ماذا عن الأجهزة متدنية الأداء؟ إنها قضية أخرى. الرسم التوضيحي أعلاه غير مفصل بما فيه الكفاية. أنا من نيجيريا، وإذا كان منتجك يعمل في إفريقيا فعليك ألا تنظر إلى ذلك الرسم، انظر إلى هذا الرسم البياني بدلًا من ذلك. في الوقت الحاضر، iPhone الأقل سعرًا يُباع في المتوسط بسعر 300 دولار أمريكي، ولا يستطيع المواطن الأفريقي العادي تحمل تكاليفه على الرغم من أن iPhone يمثل عتبة لقياس الأجهزة السريعة. هذا هو كل تحليل الأعمال الذي تحتاجه لفهم أن نطاق CSS لا يقلل من الصور المتجاوبة. على حال، هل تعرف حقًا ما هي الصور؟ الفروق الدقيقة في الصور تُعدُّ الصور جاذبة للمستخدمين ولكنها تمثل تحديًا صعبًا للمطورين حيث يجب عليهم مراعاة النقاط التالية: الشكل حجم القرص تجسيد البعد (عرض المخطط والارتفاع في المتصفح) الأبعاد الأصلية (العرض والارتفاع الأصلي) نسبة العرض إلى الارتفاع لذا، كيف نختار المعاملات الصحيحة ونطبقها بمهارة لتقديم تجربة مثالية لجمهور المستخدمين؟ تعتمد الإجابة بدورها، على إجابات هذه الأسئلة: هل الصور التي تم إنشاؤها ديناميكيًا بواسطة المستخدم أم بشكل ثابت بواسطة فريق تصميم؟ إذا تم تغيير عرض الصورة وارتفاعها بشكل غير متناسب، فهل سيؤثر ذلك على جودة الصورة؟ هل يتم عرض جميع الصور عند تقديمها بنفس العرض والارتفاع؟ هل يجب أن يكون لديهم نسبة عرض إلى ارتفاع محددة أو نسبة مختلفة تمامًا؟ ما الذي يجب مراعاته عند تقديم الصور بطُرق عرض مختلفة؟ دون إجاباتك على هذه الأسئلة فهي لن تساعدك فقط في فهم صورك ومصادرها ومتطلباتها الفنية وما إلى ذلك، ولكن ستمكنك أيضًا من اتخاذ الخيارات الصحيحة في توفيرها وعرضها على المستخدم النهائي. الاستراتيجيات المشروطة لتوصيل الصور وعرضها على المستخدم تطور تسليم الصور من إضافة بسيطة لعناوين URL إلى خاصية src الخاصة بالصور إلى سيناريوهات معقدة. قبل الخوض فيها، دعنا نتحدث عن الخيارات المتعددة لتقديم الصور بحيث يمكنك ابتكار إستراتيجية حول كيفية تسليم الصور خاصتك وتصييرها وعرضها على المستخدم النهائي. أولاً، حدِّد مصادر الصور، إذ يمكن بهذه الطريقة تقليل عدد حالات الغموض واللبس ويمكنك معالجة الصور بأكبر قدر ممكن من الكفاءة. بشكل عام، الصور إما أن تكون: ديناميكية: يتم تحميل الصور الديناميكية من قبل المستخدمين، بعد أن تم إنشاؤها بواسطة أحداث أخرى في النظام. ثابتة: يتم إنشاء هذه الصور من قبل مصور، أو مصمم، أو أنت (المطور) لموقع الويب. دعنا نتعرف إلى إستراتيجية كلًا هذين النوعين من الصور. استراتيجية الصور الديناميكية الصور الثابتة سهلة الاستخدام إلى حد ما؛ من ناحية أخرى، الصور الديناميكية معقدة وعرضةً للمشاكل. ما الذي يمكن فعله للتخفيف من حدة طبيعتها الديناميكية وجعلها أكثر قابلية للتنبؤ بها مثل الصور الثابتة؟ هناك شيئان هما: التحقق من الصحة (validation) والاقتصاص الذكي للصور (intelligent cropping). التحقق من الصحة ضع بعض القواعد للمستخدمين حول ما هو مقبول وما هو غير مقبول. في الوقت الحاضر يمكننا التحقق من صحة جميع خصائص الصورة، هذه الخصائص تتلخص بالنقاط التالية: الصيغة حجم القرص الأبعاد نسبة العرض إلى الارتفاع ملاحظة: يتم تحديد حجم الصورة أثناء التصيير (rendering)، وبالتالي لا يتم التحقق من صحة الصور من جانبنا. بعد التحقق من الصحة، ستظهر مجموعة يمكن التنبؤ بها من الصور التي يسهل استخدامها. الاقتصاص الذكي للصور تتمثل الاستراتيجية الأخرى للتعامل مع الصور الديناميكية في اقتصاصها بذكاء لتجنب حذف محتوى مهم وإعادة التركيز على المحتوى الأساسي. هذا صعب ومع ذلك يمكنك الاستفادة من الذكاء الاصطناعي الذي توفره أدوات مفتوحة المصدر أو شركات SaaS التي تتخصص في إدارة الصور. بمجرد أن يتم الانتهاء من تنفيذ هذه الإستراتيجية للصور الديناميكية، أنشئ جدول قواعد به جميع خيارات التخطيط للصور. أدناه مثال يجدر بك النظر في تحليلاته لتحديد أهم الأجهزة وأحجام الإطار المعروض (viewport). الحد الأدنى (شبه الأمثل) الآن، ضع جانبًا تعقيدات الاستجابة وانظر للمثال التالي - شيفرة HTML بسيطة مع CSS ذا أقصى عرض. تعرض الشيفرة التالية بعض الصور: <main> <figure> <img src="https://res.cloudinary.com/...w700/ps4-slim.jpg" alt="PS4 Slim"> </figure> <figure> <img src="https://res.cloudinary.com/...w700/x-box-one-s.jpg" alt="X Box One S"> </figure> <!-- More images --> <figure> <img src="https://res.cloudinary.com/...w700/tv.jpg" alt="Tv"> </figure> </main> ملاحظة: علامة الحذف (…) التي تمثل استراتيجية الاقتصاص في عنوان URL الخاص بالصورة أو المجلد. يوجد الكثير من التفاصيل التي يجب تضمينها، لكن الاقتصاص للتركيز هو ما يهم الآن. للحصول على الإصدار الكامل، انظر مثال CodePen أدناه. هذه هي أقصر شيفرة CSS موجودة على الإنترنت تجعل الصور سريعة الاستجابة: /* الحاوية الأب */ main { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } img { max-width: 100%; } إذا لم يكن للصور عرض وارتفاع متساويان، بدلِّ object-fit مكان max-width واضبط القيمة إلى cover. يشرح منشور مدونة Jo Franchetti عن التنسيقات الشائعة المتجاوبة مع تخطيط CSS كيف أن قيمة grid-template-columns تجعل التخطيط بأكمله متجاوبًا. ما سبق ليس ما نبحث عنه، لأن: حجم الصورة ووزنها متماثلان في كل من الأجهزة المتطورة وغير المتطورة. قد نرغب في أن نكون أكثر صرامة مع عرض الصورة بدلًا من تعيينها على 250 ويتغير حجمها فيما بعد. حسنًا، يغطي هذا القسم «الحد الأدنى»، لذلك هذا كل شيء. اختلافات التخطيط أسوأ شيء يمكن أن يحدث لتخطيط الصور هو سوء تدبير وإدارة التوقعات. نظرًا لأن الصور قد يكون لها أبعاد مختلفة (العرض والارتفاع)، يجب أن نحدِّد كيفية تقديم وعرض هذه الصور. هل يجب علينا اقتصاص جميع الصور بذكاء لتصبح ذات أبعاد منتظمة؟ هل يجب أن نحتفظ بنسبة العرض إلى الارتفاع لجهة العرض ونغير النسبة لشيء آخر؟ الخيار لنا. في حالة وجود صور في شبكة، مثل تلك الموجودة في المثال أعلاه مع نسب أبعاد مختلفة، يمكننا تطبيق تقنية الاتجاه الفني (art direction) لتصيير وعرض الصور، إذ يمكن أن يساعد في تحقيق شيء مثل هذا: انظر المثال أدناه: <main> <figure> <picture> <source media="(min-width: 900px)" srcset="https://res.cloudinary.com/.../c_fill,g_auto,h_1400,w_700/camera-lens.jpg"> <img src="https://res.cloudinary.com/.../c_fill,g_auto,h_700,w_700/camera-lens.jpg" alt="Camera lens"> </picture> </figure> <figure> <picture> <source media="(min-width: 700px)" srcset="https://res.cloudinary.com/.../c_fill,g_auto,h_1000,w_1000/ps4-pro.jpg"></source> </picture> <img src="https://res.cloudinary.com/.../c_fill,g_auto,h_700,w_700/ps4-pro.jpg" alt="PS4 Pro"> </figure> </main> بدلاً من تقديم صورة واحدة بعرض 700 بكسل، نعرضها بشكل 700 بكسل × 700 بكسل فقط في حال إذا تجاوز عرض منفذ العرض 700 بكسل. إذا كان حجم العرض أكبر، فسيحدث التالي: يتم تصيير صور عدسة الكاميرا كصورة عرضية تبلغ 700 بكسل وعرضها 1000 بكسل في الارتفاع (700 بكسل × 1000 بكسل). يتم عرض صور PS4 Pro بدقة 1000 بكسل × 1000 بكسل. الاتجاه الفني (Art direction) قد نحذف المحتوى الأساسي عن غير قصد عن طريق اقتصاص الصور لجعلها أكثر استجابة. كما ذُكر سابقًا، يمكن أن تساعد أدوات الذكاء الصنعي AI مفتوحة المصدر على الاقتصاص بذكاء وإعادة التركيز على الكائنات الأساسية للصور، بالإضافة إلى ذلك يعد منشور Nadav Soferman عن الاقتصاص الذكي بمثابة دليل إرشادي مفيد. شبكة دقيقة وممتدة (Strict grid and spanning) المثال الأول على الصور سريعة الاستجابة في هذا المقال هو مثال رائع. عند عرض 300 بكسل كحد أدنى، تتدفق عناصر الشبكة تلقائيًا إلى مكانها وفقًا لعرض الإطار المعروض من النافذة (viewport). من ناحية أخرى، قد نرغب في تطبيق قاعدة أكثر صرامة على عناصر الشبكة بناءً على مواصفات التصميم. تكون استعلامات الوسائط في هذه الحالة مفيدة. بدلاً من ذلك، يمكننا الاستفادة من قدرة الشبكة الممتدة grid-span لإنشاء عناصر شبكية ذات طول وعرض مختلف. @media(min-width: 700px) { main { display: grid; grid-template-columns: repeat(2, 1fr); } } @media(min-width: 900px) { main { display: grid; grid-template-columns: repeat(3, 1fr) } figure:nth-child(3) { grid-row: span 2; } figure:nth-child(4) { grid-column: span 2; grid-row: span 2; } } بالنسبة لصورة تبلغ مساحتها 1000 بكسل × 1000 بكسل على منفذ عرض واسع، يمكننا توسيعها لالتقاط خليتين من الشبكات في كل من الصف والعمود. يمكن أن تأخذ الصورة التي تتغير إلى اتجاه عمودي (700 بكسل × 1000 بكسل) على حجم أوسع من الإطار المعروض خليتين على التوالي. التحسين التصاعدي (Progressive optimization) التحسين غير المدروس ليس ذو فائدة كما لو أنه لم يحصل أي تحسين. لا تركز على التحسين دون تحديد القياسات المناسبة، ولا تقوم به إذا لم يتم دعمه بالبيانات اللازمة. ومع ذلك، يوجد مجال واسع للتحسين في الأمثلة المذكورة أعلاه. لقد بدأنا بالحد الأدنى، وأظهرنا لك بعض الحيل الرائعة، السؤال التالي الذي يجب طرحه هو: «إذا كانت الصفحة تحتوي على 20-100 صورة، فما مدى جودة تجربة المستخدم؟» فيما يلي الإجابة، يجب أن نضمن أنه في حالة وجود العديد من الصور للعرض أن يكون حجمها يناسب الجهاز الذي يعرضها. لتحقيق ذلك، نحتاج إلى تحديد عناوين URL لعدة صور بدلًا من صورة واحدة. سيختار المتصفح الصورة الأنسب لعرض الجهاز منها (الصورة ذات العرض الأمثل) وفقًا للمعايير. وتسمى هذه التقنية تبديل الدقة (resolution switching) في الصور سريعة الاستجابة. انظر مثال هذه الشيفرة: <img srcset="https://res.cloudinary.com/.../h_300,w_300/v1548054527/ps4.jpg 300w, https://res.cloudinary.com/.../h_700,w_700/v1548054527/ps4.jpg 700w, https://res.cloudinary.com/.../h_1000,w_1000/v1548054527/ps4.jpg 1000w" sizes="(max-width: 700px) 100vw, (max-width: 900px) 50vw, 33vw" src="https://res.cloudinary.com/.../h_700,w_700/v1548054527/ps4.jpg 700w" alt="PS4 Slim"> تشرح تغريدة هاري روبرتس بشكل حدسي ما يحدث: عندما جربت تقنية تبديل الدقة لأول مرة، شعرت بالارتباك وغردت ب: رفعت القبعة إلى جيسون جريجسبي للتوضيح الذي أدلى به. بفضل تقنية تبديل الدقة، إذا تم تغيير عرض نافذة المتصفح، فإنه يقوم بتنزيل الصورة الصحيحة المناسبة لحجم الإطار المعروض آنذاك من النافذة؛ وبالتالي، تُستخدَم الصور الصغيرة للهواتف الصغيرة (مناسبة لوحدة المعالجة المركزية وذاكرة الوصول العشوائي) والصور الأكبر لعرض نافذة أكبر. يوضح الجدول أعلاه أن المتصفح يقوم بتنزيل نفس الصورة (المستطيل الأزرق) بأحجام مختلفة للقرص (المستطيل الأحمر). يعد تطبيق Respp Image Breakpoints Generator من Cloudinary المجاني والمفتوح المصدر مفيدًا للغاية في تكييف صور موقع الويب مع أحجام شاشات متعددة. ومع ذلك في كثير من الحالات، سيكون إعدادات srcset و sizes وحدها كافية. الخلاصة تهدف هذه المقالة إلى توفير إرشادات بسيطة وفعالة لإعداد صور وتخطيطات سريعة الاستجابة في ضوء العديد من الخيارات المتاحة وأحيانًا المربكة. تعرّف على CSS Grid والاتجاه الفني (Art Direction) وتبديل الدقة (Resolution Switching) وستكون مبدعًا في وقت قصير في مجال الصور المتجاوب. استمر بالتعلم! ترجمة -وبتصرف- للمقال Planning for Responsive Images لصاحبه Chris Nwamba
  7. أنا متأكد تمامًا من أنك تفهم أهمية قائمة التنقل في موقع الويب وارتباطها بمشاركة الموقع فيما يلي عشر نصائح لجعل تجربة المستخدم UX سلسلة وأكثر قابلية للاستخدام. تعد إمكانية التنقل داخل موقعك جزءًا مهمًا لأي موقع ويب من أيًا كان مجاله أو نشاطه التجاري. يُعد التنقل هذا هو الطريقة الوحيدة للتعرف على منتجاتك وخدماتك. لن يعمل محتوى التنقل الخاص بموقعك جيدًا مع جميع روابط الصفحات، إذ يجب أن تكون حذرًا في الشكل الذي سيظهر به تنقلك وما الذي سيتضمنه. إذا كنت مرتبكًا أو تبحث عن بعض الاقتراحات حول ما يجب مراعاته عند تصميم قائمة التنقل في الموقع، فهناك ثماني نقاط لمساعدتك! 1. التنقل الثابت يعد وجود شريط تنقل ثابت في أعلى صفحة الموقع مفيدًا جدًا للزائرين حيث يمنحهم سهولة حقيقة عند التنقل في موقع الويب الخاص بك. بفرض أن موقعك يحتوي شريط تنقل أفقي، فسيمرر زائر الموقع وصولًا لنهاية الصفحة ثم قد يريد بعد ذلك إلقاء نظرة على صفحة «حول الموقع» (About Our Website)! سيحتاج آنذاك إلى التمرير طويلًا للأعلى للعثور على رابط الصفحة المنشودة .القائمة الثابتة في أعلى الصفحة تساعدك على حل هذه المشكلة. يرجى التأكد من ظهور عناصر قائمة التنقل الأفقية في أعلى الصفحة كما هي على جميع أحجام الشاشة المختلفة. أنا أتحدث عن مختلف أحجام شاشات الكمبيوتر والحواسيب المحمولة .يساعدك توحيد التنقل في موقعك على توفير تجربة متسقة على جميع الأجهزة. 2. الاهتمام بعملية التنقل على نسخة الهاتف المحمول لا يمكنك تجاهل زائري الجوال لموقعك. وفي عصر تصميم مواقع الويب للهواتف المحمولة أولًا، كانت الأطر سريعة الاستجابة مثل bootstrap توجهك لإيلاء الاهتمام المناسب لنظام التنقل في الأجهزة المحمولة لموقع الويب الخاص بك. الجوانب السلبية الوحيدة لنظام التنقل في موقع الويب خاصتك عبر الأجهزة المحمولة هي أنهم لا يحصلون على دعم الحومان (hover). لذلك، إذا كنت قد كتبت استعلام الوسائط (media query) بطريقة تعتمد على التنقل مع تأثيرات الحومان (hover)، قد تبدو موحدة على الأجهزة المحمولة ولكنها لن تؤدي نفس العمل. في حين أن إطار العمل bootstrap لديه دعمًا جيدًا لنظام التنقل لكل من عرض الهاتف المحمول والحاسوب. مع ذلك فإنه يحتوي على أنماط جامدة. تأكد أثناء بنائك نظام التنقل الخاص بموقعك عدم مبالغتك في استخدام شيفرة JavaScript التي قد تعطي للمستخدمين تأثيرًا مرئيًا رائعًا ولكنها تسبب صعوبة لبرامج الزحف (crawlers) لمثل Googlebot عند الزحف إلى نظام التنقل الخاص بموقعك وفهمه. إن جعل نظام التنقل الخاص بموقعك مستحيل الزحف هو أسوأ شيء يمكنك القيام به أثناء بنائه. على الرغم من أن تجربة المستخدم هي أهم أولوياتنا، إلا أننا بالتأكيد لا نستطيع تجاهل هذه القضية. 3. وضع شريط للبحث بقدر ما يتعلق الأمر بتجربة المستخدم، فإن جعل موقعك قابلاً للبحث هو أفضل شيء يمكنك القيام به على الإطلاق في موقعك. إذا كان موقعك يحتوي على الكثير من الصفحات، فيجب أن يكون في أولويتك أن تجعله قابلًا للبحث. كان هناك دائمًا تردد حول أين يجب أن أضع شريط البحث؟ كيف يمكنني ملاحظة مربع البحث الخاص بي دون تشتيت انتباه المستخدم أو التأثير على تجربة المستخدم؟ لقد قرأت مقالتين تقترحان إبقاء مربع البحث مخفيًا خلف أيقونة بارزة يجلب النقر عليها لك مربع البحث، وسيؤدي إدخال استعلام البحث وطلبه إلى إنجاز المهمة. وقرأت أيضًا بعض الدراسات حول إخفاء مربع البحث خلف أيقونة بارزة سيؤدي إلى إرباك المستخدمين حول كيفية البحث في موقع الويب هذا وماذا سيفعل هذا الرمز! بالإضافة إلى ذلك، ساهمت هذه القضية في عدد أقل من عمليات البحث في بعض مواقع الويب. لذا، أقترح أن يكون لديك مربع بحث مرئي في نظام التنقل الخاص بك، لا تخفيه في أي مكان لتوفير مساحة قليلة من البكسلات، وإذا أردت أن يكون مربع البحث الخاص بك ملفتًا للمستخدمين، يمكنك وضعه على الجانب الأيسر من التنقل، تمامًا مثل Facebook و YouTube! 4. قائمة أفضل تنظيما قد يكون لديك الكثير من المنتجات أو الخدمات لتضمينها في تصفح موقع الويب الخاص بك. سيكون من الجيد أن تتمكن من تنظيمها وفق ترتيب ما. إذا كان لديك عددًا كبيرًا من العناصر للتنقل بينها في موقع الويب الخاص بك، فيمكنك التفكير في بناء قائمة ضخمة لتجميع عناصر القائمة التي لها نفس الأصل معًا. كما لو كنت وكالة إنشاء تقدم خدمات تصميم متنوعة من الرسوم والويب وتطبيقات الهاتف المحمول وغيرها الكثير، ثم قد تفكر في تصميم الجرافيك كفئة رئيسية لك تحوي خدمات مثل تصميم الكتب، وتصميم المنشورات، وتصميم الشعارات . تجميع الأشياء تجعل القراءة السريعة للزائرين سهلة عند التنقل. بالإضافة إلى ذلك، يساعدهم في تحديد موقع العناصر المطلوبة فقط من خلال النظر في تصنيف المجموعة. هذا يجعل القراءة السريعة والبحث سهلًا بعض الشيء. أود أن أقترح عليك أن تتجنب العدد الكبير جدًا من عناصر القائمة الفرعية. إن امتلاك قائمة يصل عدد عناصرها الفرعية إلى سبعة عناصر يُسهِّل على الزائرين للموقع فهم العنصر (العناصر) المطلوبة والعثور عليها بسهولة. ضع في حسبانك قاعدة واحدة وهي أنَّ زوار موقعك سيهتمون بأول عنصر في القائمة وآخر عنصر فيها. تأكد من وضع الروابط على كلا موقع العنصريين. إن وجود زر التحقق / رابط الذي يميز نفسه مع عناصر التنقل الأخرى سيزيد من فرصة النقر عليه. 5. القائمة العمودية حسنًا، أعرف أن القائمة الرأسية هي طريقة المدرسة القديمة لتنظيم روابط التنقل. انتظر أنا لا أتحدث عن استبدال قائمتك الأفقية الرائعة بقائمة رأسية. أنا أقترح عليك أن يكون لديك قائمة رأسية لصفحاتك الداخلية حيث تحتاج إلى إظهار بعض الخيارات المتداخلة. هناك بعض الحالات التي تحتاج فيها إلى إظهار قائمة إضافية للصفحة. وجود قائمة أفقية أخرى سيؤدي بالتأكيد إلى زعزعة تجربة المستخدم الخاصة بك. هل أنت على دراية بتصاميم مواقع التجارة الإلكترونية؟ هل شاهدت تصميم الصفحة عندما تضغط على قسم الحاسوب؟ أنا أتحدث عن القائمة الرأسية نفسها للصفحات الداخلية حيث يمكنك عرض خيارات إضافية، وروابط، ومعلومات، وعناصر أخرى. يساعدك هذا على جعل التنقل في موقع الويب الخاص بك منظمًا وواضحًا. سيشاهد الزوار القائمة الرأسية فقط عند زيارة الصفحات الداخلية. 6. تقييم عناصر القائمة يوجد سوء فهم في أن جميع الزوار يأتون إلى موقع الويب الخاص بك من خلال الصفحة الرئيسية. تحقق من تحليلاتك، إذ لديك نقاط دخول متعددة للموقع. بمعنى أن عناصر التنقل ليست هي المكان الذي سيذهب منه زائرو موقعك إلى صفحات المنتج أو الخدمات الأكثر تفصيلًا. نتيجة البحث الأساسية هي من تنقلهم إلى تلك الصفحات. لذلك، ليس عليك دائمًا تضمين كل رابط / صفحة في التنقل الخاص بموقعك. احتفظ فقط بالعناصر المهمة حقًا لعملك والعناصر التي يُنقَرعليها عند التنقل. قد تكون الأداة Google Analytics أفضل طريقة لك لمعرفة روابط التنقل التي يتم النقر عليها. وترشِّح الأداة Goto Behavio Filter النتيجة التي تبدأ بـ / أو الصفحة الرئيسية. يساعدك ذلك على فهم ما هي عناصر القائمة التي يهتم بها زوار موقعك. طبّق نفس الشيء على الصفحات التي تتحكم في حركة سير موقع الويب الخاص بك للحصول على فكرة أفضل عما يجب الاحتفاظ به وما الذي يجب تغييره وتخطيه. بمجرد الانتهاء من هذا التدقيق، عدِّل قائمة التنقل. سيكون للتنقل الجديد عناصر أقل بكثير، وفوضى أقل، وقائمة تنقل أفضل تنظيمًا. 7. تجنب الكثير من التشعبات كما هو مذكور في النقطة أعلاه، احتفظ بالروابط المهمة فقط بناءً على سلوك الزوار. إنها تساعدك على جعل الأمور واضحة. بالإضافة إلى ذلك، تجنب وجود الكثير من تداخل التصنيفات والفئات الفرعية والعناصر. وجود مستوى واحد من التداخل مثل الصنف الأب -> العناصر، سوف يفي بالغرض بشكل جيد للغاية. 8. أشياء متنوعة بسيطة هناك بعض الأشياء المتنوعة التي يمكنك أخذها بالحسبان أثناء تصميم قائمة التنقل وهي: تجنب التصاميم الغريبة تجنب تصميم قائمة تنقل خاصة بموقعك تصميمًا غريبًا وفريدًا فقط من أجل أن تكون مختلفًا. إن إنشاء وتصميم التنقل في أضيق الحدود يختلف عن طريقة إنشاء التنقل غريب المظهر لكسب التميز. لا تفعل ذلك. قد تفهمها وتحبها، لكن زوار موقع الويب خاصتك لن يكونوا بنفس مستوى الإدراك هذا. أن تكون متسقة الاتساق يعطي طابع الانتظام .استخدم قائمة التنقل نفسها في جميع صفحات موقع الويب الخاص بك. سيجعل زائرك أكثر دراية به وسيجدون أنه من السهل تحديد العناصر المطلوبة. اجعلها واضحة تصويرية كن واضحًا عند اختيار اسم عنصر التنقل. عند النقر عليه، يجب أن تفتح الصفحة التي قصدتها في الاسم. تجنب استخدام الأسماء العامة مثل «منتجات وخدمات»، كما في النصيحة السادسة في هذه المقالة احصل على اسم وصفي للعناصر مثل تصميم الشعار، وإصلاح شاشة الجوال، وحلول تخطيط موارد المؤسسات، وربط بوابة الدفع. قم بتجريبها أعلم أنك تستخدم بعض إطارات العمل الموثوقة مثل bootstrap لتصميم موقع الويب وقائمة التنقل. لكن احتفظ ببعض الوقت واختبر قائمة التنقل على جميع متصفحات الويب الرئيسية. تحقق من الوظيفة على كل من إصدار سطح المكتب من المتصفح وكذلك إصدارات الأجهزة المحمولة. الخلاصة لا يتطلب الأمر سوى استخدام بيانات موقع الويب والأفكار الإبداعية وبعض الاهتمامات الشائعة لإنشاء قائمة تنقل قابلة للاستخدام بشكل جيد وجذابة للغاية. ستساعدك النقاط الثمانية التي تمت مناقشتها هنا في تحديد ما يجب القيام به مع قائمة التنقل الخاصة بك التالية. ترجمة -وبتصرف- للمقال Eight tips to make website navigation menu more usable لصاحبه Darshan