<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; JavaScript</title><link>https://academy.hsoub.com/programming/javascript/page/16/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; JavaScript</description><language>ar</language><item><title>&#x623;&#x64A;&#x651;&#x647;&#x645;&#x627; &#x623;&#x641;&#x636;&#x644; &#x644;&#x644;&#x62A;&#x62D;&#x631;&#x64A;&#x643; Animations&#x61F; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; &#x623;&#x645; CSS&#x61F;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A3%D9%8A%D9%91%D9%87%D9%85%D8%A7-%D8%A3%D9%81%D8%B6%D9%84-%D9%84%D9%84%D8%AA%D8%AD%D8%B1%D9%8A%D9%83-animations%D8%9F-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D8%A3%D9%85-css%D8%9F-r42/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_03/css-javascript_480x300.png.2a497e9f1d6af869820e1c1f0abf68c7.png" /></p>
<p>هناك اعتقاد خاطئ بين العديد من مطوّري الويب أن CSS هي الطريقة الوحيدة للقيام بالتحريك Animations. برزت CSS بقوة كأكثر نظام مُدلّل خلال سنوات وحتى الآن، وتحدّث المطوّرون باستمرار حول متانتها وتوافقها مع الهواتف. CSS جيدة لكنها ليست أفضل من جافاسكربت. هناك بعض الأساطير حول CSS قادت المطوّرين بشكل استباقي لتبنّي هذا النظام (أي CSS) والتخلي عن كلٍّ من جافاسكربت والتحريك الخاصّ بها.</p><p>ما يحيّر المطوّرين هو الاستخدام الفعّال لـ CSS، فبينما يقومون بإدارة التفاعل بين العناصر من داخل CSS، يُجبرون أنفسهم أيضًا على جعل مشروعهم متوافقًا مع Internet Explorer 8 و 9، وأخيرًا، يتجنّبون التحريك الجاهز الذي لا يتوفر إلا عن طريق جافاسكربت.</p><p>يهدف هذا المقال لدحض بعض الأساطير حول CSS وكشف جميع المشكلات الأساسية التي بالكاد يتحدث الناس عنها بسبب إعجابهم بـ CSS. يهدف المقال إلى رفع معرفتك ووعيك بفوائد استخدام جافاسكربت، حتى يمكنك بسهولة التخلص من المواقف التي تثير غضبك.</p><p>لذا، دون مزيد من الإطالة دعونا نتناقش حول كل منهم بالتفصيل.</p><h2>1. jQuery</h2><p>دعونا نبدأ بالأساسيات، يتم الربط بين جافاسكربت ومكتبة jQuery بشكل خاطئ . فالتحريك المُصمَّم بجافاسكربت سريع ومرن، بينما المُصمَّم بـ jQuery بطيء. السبب أنه -وبرغم مواصفات jQuery القوية- إلّا أنها لم تهدف بشكل رئيسي لتنفيذ التحريك. هناك العديد من الأسباب لدعم هذا:</p><ul><li>لا يمكن لمكتبة jQuery ببساطة أن تتوقف عن تحطيم التنسيق (layout thrashing) نظرًا لهيكلتها البرمجية التي تخدم عددًا من الأغراض غير التحريك. هذا بشكل عام يسبب تقطّعًا في المراحل الأولى من التحريك.</li><li>الذاكرة التي تستهلكها jQuery دومًا تُحفّز جمع القمامة (Garbage Collection) مما يؤدي إلى تجمّد التحريك. ونظرًا لـ جمع القمامة، يمكن للمرء أن يواجه تقطّعًا أثناء التحريك.</li><li>تم تصميم jQuery لتستخدم <span style="font-family:'courier new', courier, monospace;">set_interval()</span> وليس طلب إطار الحركة (Request Animation Frame - RAF). عندما لا يكون طلب إطار الحركة موجودًا فيمكن أن ينتج عن ذلك تحريكات بعدد إطارات منخفض (جودة ودقة الحركة تعتمد على عدد الإطارات التي تظهر في الثانية، العدد المثالي هو 60 إطار في الثانية).</li></ul><h2>2. فقر التحكم بالتدوير وتحديد الموقع</h2><p>من الميزات الأساسية الضرورية أثناء تنفيذ التحريك استخدام المُتحكّمات لـ: التحريك animation، التدوير rotation، وتحديد المواقع positioning. في CSS، تم تكديس جميع هذه الدوالّ في خاصية معروفة هي <span style="font-family:'courier new', courier, monospace;">tranform</span>. هذه الخاصية تُسبب مشاكل عند تحريك شيء ما بطريقة فريدة عن طريق عنصر مشترك. على سبيل المثال، إن أردت تحريك “التدوير” <span style="line-height:11.1999998092651px;">rotation</span> و”التكبير” scaling بشكل منفصل، وباستخدام أزمنة مختلفة، فهذا مُمكن فقط عن طريق جافاسكربت ﻷنها تُمكّنك من استخدام حِيل متنوعة، وهذه غير مسموحة في CSS. هذه إحدى مساوئ CSS. هي جيدة من أجل مشاريع تتطلب تحريكاتٍ بسيطة وليس من أجل المشاريع التي تتطلب اندماج تصميمٍ بتحريكاتٍ كبيرة.</p><h2>3. الأداء مع مكتبتيّ Velocity وGSAP</h2><p>Velocity وGSAP هما المكتبتان الرائدتان والأكثر شعبية في جافاسكربت. كلاهما يعمل مع jQuery أو بدونها. عندما يتم استخدام أيّ من هاتين المكتبتين جنبًا إلى جنب مع jQuery فلا يحدث أي تدهورأو تباطؤ في الأداء لأنهما تعملان بشكل منفصل عن تحريكات jQuery الأساسية.</p><p>ويمكن أيضًا استخدام هاتين المكتبتين بسهولة عندما لا تكون مكتبة jQuery موجودة في الصفحة. وهذا يبين بوضوح أنه بدلًا من ربط جميع أنواع استدعاءات التحريك في عنصر jQuery مشترك يمكنك بشكل مباشر تمرير العنصر المراد إلى استدعاء الحركة كما هو مبين أدناه.</p><pre class="javascript ipsCode prettyprint">/* Working without jQuery */
Velocity(element, { opacity: 0.4 }, 900); // Velocity
TweenMax.to(element, 1, { opacity: 0.4 }); // GSAP
</pre><p><span style="line-height:1.6;">في المثال السابق، يمكنك ملاحظة أن Velocity تستخدم نفس الصيغة حتى عندما لا يتم استخدام jQuery. قامت فقط بإزاحة جميع العناصر تجاه اليمين لترك مساحة للعناصر المستهدفة.</span></p><p>بالمقابل، في GSAP تم استخدام تصميم كائني التوجه (عن طريق استدعاء كائن يمثّل صنف Class) جنبًا إلى جنب مع دالّة بسيطة ثابتة. بهذه الطريقة المستخدم يملك تحكم كامل بعملية الحركة.</p><h2>4. معامل وحدة معالجة الرسوم (GPU)</h2><p>عندما تكون وحدة معالجة رسوم GPU مُحسّنة بشكل كامل، عندها ستكون عظيمة لأداء مهام متنوعة كالتعامل مع مصفوفات التحويل transform والشفافية opacity، لهذا السبب أول ما تفعله جميع المتصفحات المتطورة هو تفريغ هذه المهام من وحدة المعالجة المركزية CPU إلى وحدة معالجة الرسوم GPU. الهدف الأساسي هو فصل جميع العناصر المتحركة إلى طبقات خاصة بها في وحدة معالجة الرسوم ﻷنه فور انتهاء النظام من إنشاء طبقات وحدة معالجة الرسوم لا يُظهر النظام أي اهتمام بتحريك البكسلات وجمعهم معًا. لهذا لا يوجد حاجة بتاتًا لحساب كل بكسل بشكل مستمر. بدلًا من ذلك يمكن تحريك بكسل واحد فوق الآخر وتوفير كثير من الوقت.</p><p><strong>ملاحظة</strong>: لا حاجة لإعطاء كل عنصر طبقته الخاصة نظرًا لذاكرة الفيديو المحدودة في وحدة معالجة الرسوم. فإذا نفدت الذاكرة سيفسد كل شيء.</p><p>من ناحية أخرى، إذا قمتَ بتعريف التحريك في CSS عندئذ ستكون مهمة المتصفح أن يحدد طبقة وحدة معالجة الرسوم لكل عنصر وسيحصل انقسام بسبب ذلك.</p><p>مع ذلك، يمكنك عمل هذا الأمر عن طريق جافاسكربت أيضًا. كل ما تحتاجه هو تحديد التحويل transform مع خاصية 3D (تمامًا مثل <span style="font-family:'courier new', courier, monospace;">translate3d()</span> و <span style="font-family:'courier new', courier, monospace;">matrix3d()</span>) لجعل المُتصفح يعلم عن عملية إنشاء طبقات وحدة معالجة الرسوم للعنصر المستهدف. لذا، فمن الواضح أن وحدة معالجة الرسوم لا توفّر زيادة السرعة لـ CSS فقط بل لجافاسكربت أيضًا.</p><h2>5. قوة تحريك جافاسكربت</h2><p>لدى جافاسكربت كل الإمكانيات للفوز بمقارنة الأداء مع CSS. جافاسكربت هي أسرع. لكن إلى أي حدّ يمكن أن تكون أسرع؟ بدايةً هي مرنة بما فيه الكفاية لإنشاء عرض تحريك ثلاثيّ الأبعاد 3D ملفت للنظر، الذي يمكن أن تراه عبر WebGL. وجافاسكربت سريعة بشكلٍ كافٍ لبناء دعاية وسائط متعددة، والتي كان من الممكن تطويرها باستخدام Flash أو After Effects. وبالتأكيد بناء عالم افتراضي باستخدام جافاسكربت بمساعدة Canvas.</p><p>بقدر ما تكون مكتبات التحريك هي المعنية في هذا المقال، فإن الحديث الآن عن توثيق مكتبتيّ Transit و Velocity غير مبرر على الإطلاق. لمزيد من التوضيح لهذه النقطة، قمنا بطرح قائمة تحسينات يمكن فقط للتحريك المبنيّ بجافاسكربت أن يؤديها:</p><ul><li>مزامنة DOM</li><li>التخزين المؤقت للخصائص عبر سلسلة من الاستدعاءات، للتخفيف من استعلامات DOM</li><li>التخزين المؤقت لنسب تحويل الواحدات</li></ul><h2>خلاصة</h2><p>نجد بوضوح كيف أن النقاط المذكورة أعلاه تسلط الضوء على براعة التحريك المبنيّ على جافاسكربت بالمقارنة مع المبنيّ على CSS. ولكن هل هذا يعني أن تحريك CSS “سيّء”؟ بالتأكيد لا. هو جيّد لأداء تحريك بسيط. لكن لمرونة وقدرات فريدة أعلى، يجب أن تأخذ جافاسكربت بعين الاعتبار.</p><p>ترجمة -وبتصرفّ- للمقال <a rel="external nofollow" href="http://www.script-tutorials.com/css-vs-javascript-myths-fall-to-pieces/">CSS Vs JavaScript Myths Fall to Pieces</a></p>
]]></description><guid isPermaLink="false">42</guid><pubDate>Tue, 17 Mar 2015 08:41:00 +0000</pubDate></item><item><title>&#x645;&#x627; &#x627;&#x644;&#x62C;&#x62F;&#x64A;&#x62F; &#x641;&#x64A; &#x627;&#x644;&#x625;&#x635;&#x62F;&#x627;&#x631; &#x627;&#x644;&#x642;&#x627;&#x62F;&#x645; &#x645;&#x646; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; (ECMAScript 6) - &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x62B;&#x627;&#x646;&#x64A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D8%A7-%D8%A7%D9%84%D8%AC%D8%AF%D9%8A%D8%AF-%D9%81%D9%8A-%D8%A7%D9%84%D8%A5%D8%B5%D8%AF%D8%A7%D8%B1-%D8%A7%D9%84%D9%82%D8%A7%D8%AF%D9%85-%D9%85%D9%86-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-ecmascript-6-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-r26/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_03/es6.jpg.cc6bc13c82851b4f19fcd90990b8b334.jpg" /></p>
<h2>التفكيك Destructuring</h2><p>ذكرنا في الجزء السابق أن اهتمامًا كبيرًا أُوليَ لتسهيل كتابة الشفرة وقراءتها في ECMAScript 6، و<strong>الإسناد بالتفكيك (Destructuring assignment)</strong> لا يخرج عن هذا السياق، وهو ليس بالمفهوم الجديد في عالم البرمجة، فهو معروف في Python وفي Ruby. بعيدًا عن تعقيدات المصطلحات، إليك هذا المثال:<code class="lang-javascript"> </code></p><pre class="javascript ipsCode prettyprint">var [a, b, c] = [1, 2, 3];
a == 1 // true
b == 2 // true
c == 3 // true</pre><p>ما الذي يحدث هنا؟ بكل بساطة تسمح ECMAScript 6 بصياغة جديدة للتعريف عن المتغيرات أو إسناد قيم جديدة إليها جُملةً واحدة من خلال جمعها ضمن قوسي مصفوفة (Array) وسيقوم مُفسّر اللغة بإسناد قيمة مقابلة لكل متغيّر من المصفوفة الواقعة على يمين مُعامل الإسناد (<code>=</code>). الأمر لا يقتصر على إسناد المصفوفات، بل يمكن أيضًا إسناد خصائص العناصر:</p><pre class="javascript ipsCode prettyprint">let person = { firstName: "John", lastName: "Smith", Age: 42, Country: "UK" };

let { firstName, lastName } = person;

console.log(`Hello ${ firstName } ${ lastName }!`); // Hello John Smith!</pre><p>في هذا المثال لدينا متغيّرات تتبع للنطاق العامّ <code>firstName</code> و<code>lastName</code>، وقد أسندنا لها قيمًا من خصائص الكائن <code>person</code>، حيث يبحث مفسّر اللّغة عن خصائص في الكائن <code>person</code> يماثل اسمها اسم المتغيّر المفروض ويُسندها إلى المُتغيّرات. يمكن توضيح المقصود بصورة أفضل إذا أعدنا كتابة الشفرة لتتوافق مع الإصدار الحالي من JavaScript:<code class="lang-javascript"> </code></p><pre class="javascript ipsCode prettyprint">var person = { firstName: "John", lastName: "Smith", Age: 42, Country: "UK" };

var firstName = person.firstName;
var lastName = person.lastName;

console.log("Hello " + firstName + " " + lastName + "!"); // Hello John Smith!
</pre><p>يشيع استخدام التفكيك في CoffeeScript (وهي لغة أقر Brendan Eich مُخترع JavaScript بأنّ الإصدار الأخير من JavaScript استوحى الكثير منها)، وخصوصًا عندما تُنظّم البرامج في وحدات كما في Node.js ويكون اهتمامًا مُقتصرًا على استيراد جزء مُحدّد من الوحدة المعنيّة:</p><pre class="javascript ipsCode prettyprint">{ EventEmitter } = require 'events'
{ EditorView } = require 'atom'
{ compile } = require 'coffee-script'


compile('# coffeescript code here');</pre><p>عند تحويل هذا النص إلى JavaScript الحالية، سنحصل على:</p><pre class="javascript ipsCode prettyprint">var EventEmitter = require('events').EventEmitter;
var EditorView = require('atom').EditorView;
var compile = require('events').compile;

compile('# coffeescript code here');</pre><p>من الاستخدامات المفيدة للإسناد بالتفكيك التبديل بين قيمتي متغيّرين بصورة سهلة، سنقتبس المثال من توثيق CoffeeScript ونُعيد كتابته بـJavaScript:</p><pre class="javascript ipsCode prettyprint">var theBait   = 1000;
var theSwitch = 0;

[theBait, theSwitch] = [theSwitch, theBait];</pre><p>قبل ES6 كنا لنحتاج لكتابة مُتغيّر مؤقّت نخزن فيه قيمة إحدى المتغيّرين للاحتفاظ بها قبل التبديل بين القيمتين، وهو ما يفعله محوّل CoffeeScript بالفعل ليعطينا شفرة JavaScript متوافقة مع الإصدار الحالي (مع أنه يقوم بتخزين كلا القيمتين في مصفوفة، إلا أنّ الفكرة تبقى ذاتها):</p><pre class="javascript ipsCode prettyprint">var theBait, theSwitch, _ref;

theBait = 1000;

theSwitch = 0;

_ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1];</pre><h2>المُكرِّرات (Iterators) وحلقة <code>for... of</code></h2><p>ما من لغة برمجة تخلو من وسيلة للمرور على عدد من القيم و<strong>تكرار</strong> تنفيذ عمليّة معيّنة على هذه القيم، من أبسط هذه الوسائل حلقة <code>for</code> التقليديّة الشّهيرة، وفي JavaScript يشيع استخدام حلقة <code>for... in</code> إلى جانبها للمرور على أسماء خصائص العناصر، إذ يمكننا معرفة كل خصائص العنصر <code>document</code> بسطرين فقط:</p><pre class="javascript ipsCode prettyprint">for (var propertyName in document) {
    console.log(propertyName);
}

// "body"
// "addEventListener"
// "getElementById"
// ...</pre><p>لاحظ أن حلقة <code>for... in</code> تُعيد <strong>أسماء</strong> خصائص العنصر (كسلسة نصيّة String)، والأمر لا يستثني المصفوفات، فهي ليست سوى كائنات بأسماء خصائص توافق رقم الفهرس (Index):<code class="lang-javascript"> </code></p><pre class="javascript ipsCode prettyprint">for (var i in [1, 2, 3]) {
  console.log(i);
}

// "0"
// "1"
// "2"
</pre><p>من عيوب حلقة <code>for... in</code> أن لا شيء في تعريف اللغة يُجبر مُفسّر اللّغة على إخراج العناصر بترتيب ثابت بالضّرورة، وهذا يعني أنها تصبح مباشرة غير صالحة للمرور على المصفوفات - التي تستخدم لحفظ عناصر <em>مُرتّبة</em> - بطريقة بديهيّة، ويحلّ محلّها حلقة <code>for</code> التقليديّة عندئذٍ، وأمّا عند استخدامها للمرور على الكائنات، فإنّها لا تُعيد إلّا الخصائص الّتي تُعرّف على أنها قابلة للتعداد (enumerable)، وهو شيء يُحدّد عند تعريف الخاصّة، كما أنّها تُعيد الخصائص القابلة للتعداد التي ورثها الكائن عن "آباءه" ضمن سلسلة الوراثة، وهو تصرّف قد لا يكون مرغوبًا دومًا، وغالبًا سترى المطوّرين يُجرون فحصًا للخاصّة قبل متابعة تنفيذ الشفرة لمعرفة ما إذا كانت تخصّ العنصر ذاته أمّ أنّه ورثها:</p><pre class="javascript ipsCode prettyprint">var obj = { a: 1, b: 2, c: 3 }; // كائن جديد لا يرث سوى النموذج Object

for (var prop in obj) {
  console.log("o." + prop + " = " + obj[prop]);
}

// "o.a = 1"
// "o.b = 2"
// "o.c = 3"</pre><p>في هذا المثال (المنقول عن <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in">شبكة مطوّري موزيلا</a>) فرضنا كائنًا جديدًا بثلاث خصائص، وعند المرور عليه بحلقة <code>for... in</code> فإنّنا حصلنا على النتيجة المتوقّعة، ولم نحصل على خصائص إضافيّة لأنّ الكائن الذي فرضناه لا يرث أي كائن آخر سوى <code>Object</code> (الذي ترثه كل الكائنات افتراضًا). أما في المثال التالي، فقد احتجنا لإجراء اختبار <code>hasOwnProperty</code> على العنصر الوارث لكي لا تظهر سوى الخاصة <code>color</code> التي يملكها بذاته ولم يرثها:</p><pre class="javascript ipsCode prettyprint">var triangle = {a: 1, b: 2, c: 3};

function ColoredTriangle() {
  this.color = "red";
}

ColoredTriangle.prototype = triangle;

var obj = new ColoredTriangle();

for (var prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    console.log("o." + prop + " = " + obj[prop]);
  } 
}

// Output:
// "o.color = red"</pre><p>حسنًا، لقد أطلنا الحديث عن حلقة <code>for... in</code> وهي ليست بالجديدة؛ لكنّنا أصبحنا نرى الحاجة لشيء جديد أكثر بساطة ومرونة، فهذا ما تبتغيه ES6 في النهاية، ولهذا نشأت فكرة المُكرّرات؛ التي تسمح لأي عنصر بأن يختار لنفسه الطّريقة التي يتصرّف بها عند المرور به في حلقة، ومع المُكرّرات لا بدّ من نوع جديد من الحلقات لتلبية هذه الحاجة والمحافظة على حلقة <code>for... in</code> للتوافق مع الإصدارات القديمة. من هنا نشأت حلقة <code>for... of</code> الجديدة.</p><pre class="javascript ipsCode prettyprint">for (var num of [1, 2, 3]) {
    console.log(num);
}

// 1
// 2
// 3


for (var node of document.querySelectorAll('a')) {
  console.log(node);
}

// &lt;a class="title" href="/"&gt;
// &lt;a class="contact" href="/contact/"&gt;</pre><p>حصلنا في المثالين السابقين على <strong>قيمة</strong> الخاصّة وليس اسم الخاصّة، لكنّ هذا لا يعني أنّ حلقة <code>for... of</code> تُعيد قيم الخصائص دومًا، بل إنّها تستدعي <strong>مُكرّر</strong> الكائن (<code>Iterator</code>) وتطلب منه في كلّ دورة للحلقة تزويدها بشيء ما، وتترك للمُكرّر الحُريّة بإعادة أي قيمة يرغب بها، ولكن ولأنّنا نستدعي في مثالنا مصفوفة أولاً، وعنصر من نوع <code>NodeList</code> ثانيًا، وكلا النّوعين يُعيد مُكرُّرهما قيمَ العناصر في المصفوفة، فإنّنا نحصل على تلك النتيجة البديهيّة. بإمكاننا إنشاء أصناف بمُكرّرات خاصّة نُنشئها بأنفسنا، ولنفترض أن لدينا نوعًا لصفّ ضمن مدرسة ابتدائية، ونريد أن نحصل على تفاصيل الطلّاب على هيئة نص مُنسّق عند المرور على الصّفّ في حلقة <code>for... of</code>:</p><pre class="javascript ipsCode prettyprint">function SchoolClass(students) {
   this.students = students;
}

SchoolClass.prototype[Symbol.iterator] = function*() {
    for (let i = 0; i &lt; this.students.length; i++) {
        let student = this.students[i];
        yield `#${i+1} ${student.name} (${student.age} years old)`;
    }
}

var ourClass = new SchoolClass([ { name: "Ahmed", age: 10 }, { name: "Alaa", age: 9 }/*, ...*/ ]);
for (student of ourClass) {
     console.log(student);
}

// "#1 Ahmed (10 years old)"
// "#2 Alaa (9 years old)"
// "#3 ..." ...</pre><p>استخدمنا الرمز الخاص <code>Symbol.iterator</code> لإسناد دالّة مُولّد (Generator function) التي تُعطينا عند استدعائها نسخة من مُكرّر الصنف المُخصّص الذي أنشأناه. سنتعرف بعد قليل على المُولّدات (Generators) وكذلك على الرموز (Symbols) في وقت لاحق. لاحظ أنّنا استخدمنا حلقة <code>for... of</code> للمرور على محتويات <code>ourClass</code>.</p><p>تذكّر أنّنا استخدمنا هذه الحلقة في الجزء السابق مع Array Comprehension، كما في المثال:<code class="lang-javascript"> </code></p><pre class="javascript ipsCode prettyprint">let people = ["Samer", "Ahmed", "Khalid"];
console.log([`Hello ${person}` for (person of people)]);
</pre><p>إن كانت الفقرة الأخيرة غامضة بعض الشيء فلا تقلق، سنتوسّع بشرح المولّدات بعد قليل.</p><p>لكن دعونا نتوقّف قليلاً ولننتقل إلى الجانب الفلسفي لهذه الإضافات في JavaScript، قد تبدو للوهلة الأولى تعقيدات بلا طائل، خصوصًا وأنّ كثيرًا منها لا يهدف سوى للتسهيل، ولا يقدّم شيئًا يستحيل إنجازه بالإصدارات السابقة من اللغة؛ هنا يمكن الرّدّ بأنّ تطوّر اللغة متعلّق بكيفيّة استخدامها والخبرة التي تُكتسب مع مرور السّنين، حيث تظهر للمطوّرين حاجات جديدة وأفكار تطبّق مرارًا لدرجة أنها ترتقي لتصبح ضمن أساسات اللغة. سهولة كتابة الشفرة لم تعد رفاهية، بل هي ضرورة لإنجاز المشاريع الكبيرة لأنّها تتيح اختصار الوقت الذي كان سيضيع في كتابة متكرّرة ومُملّة، كما أنّها تُلبّي ما يتوقّعه المطوّرون من لغة أصبحت تؤخذ على محمل الجدّ وتُستخدم في تطوير تطبيقات ضخمة ومُعقّدة بعد أن كان جُلّ استخدامها تنفيذ بعض المهام البسيطة.</p><h2>المُولِّدات (Generators)</h2><p>المولدات (Generators) ببساطة هي دوال يمكن إيقافها والعودة إليها في وقت لاحق مع الاحتفاظ بسياقها دون تغيير، صياغة دوال المولدات لا تختلف كثيرًا عن صياغة الدوال التقليدية، كل ما عليك هو إضافة إشارة * بعد <code>function</code> واستخدام <code>yield</code> بدل <code>return</code>، المثال التالي سيوضح فكرة المولدات أكثر:<code class="lang-javascript"> </code></p><pre class="javascript ipsCode prettyprint">function* getName() {
  let names = ['Muhammad', 'Salem', 'Abdullah'];
  for (name of names) {
    yield name;
  }
}

let nameGenerator = getName();
nameGenerator.next().value; // 'Muhammad'
nameGenerator.next().value; // 'Salem'
nameGenerator.next().value; // 'Abdullah'
nameGenerator.next().value; // undefined

}
</pre><p>ما الذي يحدث هنا؟ فرضنا دالّة مولّد (Generator function) (والتي تُميّز بإشارة النجمة <code>*</code>) سمّيناها <code>getName</code>، وفيها صرحنا عن مصفوفة فيها أسماء، وظيفة هذه الدالة أن تعطينا عند استدعائها نسخة من مُكرّر (Iterator) (الذي شرحناه لتوّنا)، يزوّدنا بالأسماء بالترتيب في كل مرة نستدعيه فيها ليعطينا النتيجة التالية (<code>next()</code>)، أولاً يجب حفظ نسخة المُكرّر ضمن متغير لكي نسمح له بحفظ حالته، ودون ذلك سيعطينا استدعاء دالّة المولد مباشرةً <code>getName().next()</code> دوماً النتيجة الأولى لأننا عملياً نُنشئ نسخة جديدة عنه في كل مرة نستدعيه، أما استدعاء نسخة عنه وحفظها في متغير مثل <code>myGenerator</code> فيسمح لنا باستدعاء <code>.next()</code> عليها كما هو متوقع. لا ترجع الدالة <code>.next()</code> القيمة التي نرسلها عبر <code>yield</code> فقط، بل ترجع كائناً يحوي القيمة المطلوبة ضمن الخاصة <code>value</code>، وخاصة أخرى <code>done</code> تسمح لنا بمعرفة ما إذا كان المولد قد أعطانا كل شيء.</p><p>لنُعِدْ ترتيب أفكارنا:</p><ol><li><p>المولّدات تسمح <strong>بتوقّف تنفيذها مع الاحتفاظ بحالة التنفيذ</strong> (يحدث توقّف التنفيذ عند كلّ كلمة <code>yield</code>). فلو أنّنا كتبنا دالّة تقليديّة في المثال أعلاه مع <code>return</code> بدل <code>yield</code> لحصلنا في كلّ مرّة على الاسم الأول (Muhammad). وهذه الميزة في المولّدات يمكن <em>استغلالها لإنشاء حلقات لا نهائية</em> دون إعاقة متابعة البرنامج:</p><pre class="javascript ipsCode prettyprint"> function* numberGenerator() {
   for (let i = 0; true; i++) {
      yield i;
   }
 }

 let numGen = numberGenerator();
 numGen.next(); // { value: 0, done: false }
 numGen.next(); // { value: 1, done: false }
 numGen.next(); // { value: 2, done: false }
 numGen.next(); // { value: 3, done: false }
 // ...</pre></li><li><p>دوالّ المولّدات تُعطي عند استدعاءها <strong>مُكرّرات</strong>، وهذا يعني إمكانيّة استخدامها في حلقة <code>for... of</code> (احذر من تطبيق مثال كهذا على مولّد غير منتهٍ كما في المثال السابق!):</p><pre class="javascript ipsCode prettyprint"> for (let name of getName()) {
   console.log(name);
 }

 // "Muhammad"
 // "Salem"
 // "Abdullah"</pre></li><li><p>لكلّ مُكرّر وظيفة <code>.next()</code> مهمّتها بدء تنفيذ الدّالّة أو متابعة تنفيذها ثم إيقافها مؤقّتًا عند كلّ كلمة <code>yield</code>.</p></li><li>استدعاء <code>next()</code> على المُكرّر يعيد لنا في كلّ مرة كائنًا ذا خاصّتين: الأولى <code>value</code> وهي أيّ شيء نُعيده بكلمة <code>yield</code>، والثّانية <code>done</code> وهي قيمة منطقيّة (Boolean) تشير إلى حالة انتهاء تنفيذ الدّالة.</li></ol><p>تقبل الوظيفة <code>.next()</code> للمُكرّرات مُعاملاً اختياريًّا تستقبله وتُرسله لدالّة المولّد بعد متابعة التنفيذ، ويمكن استخدامها لإرسال رسائل لدالّة المولّد بحيث نؤثّر في تنفيذه:</p><pre class="javascript ipsCode prettyprint">function* numberGenerator() {
  for (let i = 0; true; i++) {
     var reset = yield i;
     if (reset) i = -1;
  }
}

let numGen = numberGenerator();
numGen.next(); // { value: 0, done: false }
numGen.next(); // { value: 1, done: false }
numGen.next(); // { value: 2, done: false }
numGen.next(); // { value: 3, done: false }

numGen.next(true); // { value: 0, done: false }</pre><p>في هذا المثال مرّرنا القيمة <code>true</code> إلى الوظيفة <code>.next()</code> على المُكرّر، والذي بدوره يُرسلها لدالّة المولّد كنتيجة <code>yeild i</code> في الدّورة الموافقة للحلقة، لنقومَ بحفظها في متغيّر <code>reset</code> ونُجريَ فحصًا عند متابعة التنفيذ لإعادة تعيين قيمة <code>i</code>، التي ستزداد بمقدار واحد مع بدء الدورة التالية لحلقة <code>for</code> جاعلةً قيمة <code>i</code> مساوية للصّفر.</p><p>خصائص المولّدات تجعلها مناسبة جدًا لكتابة شيفرة غير متزامنة بصورة أسهل تكاد تبدو فيها وكأنها شيفرة متزامنة خالية من الاستدعاءات الراجعة المتداخلة (Nested callbacks)؛ هذه الفكرة تحتاج إلى تركيز لأنها أساس لعدد من المكتبات مثل <a rel="external nofollow" href="https://github.com/tj/co">co</a> و<a rel="external nofollow" href="https://github.com/jmar777/suspend">suspend</a> التي ظهرت مؤخّرًا وتصاعدت شعبيّتها بسرعة لأنّها تحلّ مشكلة جوهرية في استخدام JavaScript، ألا وهي التعامل مع الدوال غير المتزامنة (asynchronous functions) وذلك بالاعتماد كُليًّا على المُولّدات.</p><p>لنفترض أنّ لدينا موقعًا لقراءة الكتب يعرض ملفّ المستخدم الشّخصيّ مع عدد الكتب التي قرأها وعنوان آخر كتاب مع تقييم المستخدم له:</p><pre class="javascript ipsCode prettyprint">var list = document.querySelector("#book-list");

getJSON("http://reading-website.com/users/fwz.json", function(err, user) {
    if (err) return; // افعل شيئًا بما بخصوص الخطأ

    var num_books = user.books.length;
    var most_recent_book_id = user.books[num_books - 1];

    getJSON("http://reading-website.com/users/fwz/ratings/" + most_recent_book_id + ".json", function(err, user_rating) {
        getJSON("http://reading-website.com/books/" + most_recent_book_id + ".json", function(err, book) {
            var fragment = document.createDocumentFragment();

            var h2 = document.createElement("h2");
            h2.textContent = user.full_name;

            var h3 = document.createElement("h3");
            h3.textContent = "الكتب التي قرأها";

            for (let book of books) {
                let li = document.createElement("li");
                li.textContent = book.title + (book.id == most_recent_book_id ? " " + user_rating : "");
                fragment.appendChild(li);
            }

            list.appendChild(fragment);
        });
    });

})</pre><p>في المثال السابق احتجنا إلى إرسال 3 طلبات AJAX يعتمد أحدها على الآخر، ولأنّنا لا نستطيع إرسال طلب بتقييم المستخدم للكتاب قبل معرفة مُعرّف الكتاب، فلا بدّ من أن يرسل الطلب الخاصّ بتقييم الكتاب ضمن الاستدعاء الرّاجع لطلب معلومات المستخدم، ثمّ يمكن جلب عنوان الكتاب ضمن الاستدعاء الرّاجع للطلب السّابق، وهذا يعني زيادة تعقيد الشفرة مع تداخل الاستدعاءات الرّاجعة لتبدو أشبه بسباغيتي لا تُعرف بدايته من نهايته.</p><p>تخيّلوا -لغرض التّخيّل- لو أمكننا كتابة هذه الشفرة (وهي غير متزامنة) لتبدو لقارئها وكأنها نص برمجي يسير بترتيب متزامن وبديهيّ... ألن يكون هذا أعظم شيء منذ اختراع JavaScript؟<code class="lang-javascript"> </code></p><pre class="javascript ipsCode prettyprint">var list = document.querySelector("#book-list");

try {
   var user = getJSON("http://reading-website.com/users/fwz.json");

   var num_books = user.books.length;
   var most_recent_book_id = user.books[num_books - 1];

   var user_rating = getJSON("http://reading-website.com/users/fwz/ratings/" + most_recent_book_id + ".json");
   var book = getJSON("http://reading-website.com/books/" + most_recent_book_id + ".json");

   var fragment = document.createDocumentFragment();

   var h2 = document.createElement("h2");
   h2.innerText = user.full_name;

   var h3 = document.createElement("h3");
   h3.innerText = "الكتب التي قرأها";

   for (let book of books) {
       let li = document.createElement("li");
       li.innerText = book.title + (book.id == most_recent_book_id ? " " + user_rating : "");
       fragment.appendChild(li);
   }

   list.appendChild(fragment);

} catch (e) {
   // افعل شيئًا بما بخصوص الخطأ
   // Error
}
</pre><p>نحن نعلم أن الأمور لا يمكن أن تكون بهذه الروعة، وأنّ الشفرة أعلاه لن تعمل... نحن نعلم أن شيفرتنا تحتاج تفاصيل المستخدم للحصول على الكتب، وأننا نحتاج للكتاب لجلب عنوانه وتقييمه، وتنفيذ هذه المهمّات بشكل غير متزامن لا يعني أنّه ليس علينا <strong>انتظار</strong> المهمّة الأولى قبل إطلاق الثانية - بل يعني فقط أن المتصفح يمكنه تنفيذ رسم العناصر الأخرى وعرض الصفحات وإرسال طلبات أخرى في هذا الوقت.</p><p>حسنًا، لدي خبر جيّد وآخر سيئ: أمّا الجيّد فهو أنّنا كتابة شيفرة شبيه بهذه أصبحت قريبة المنال مع الدّوالّ غير المتزامنة (Async Functions)، وأمّا الخبر السيّئ فهو أنّ علينا الانتظار إلى الإصدار 7 من ECMAScript لنستطيع كتابتها! (مع العلم أن المتصفّحات لم تنتهِ من تطبيق ES6!).</p><p>لكن هذا لا يعني أن نقف مكتوفي الأيدي إلى أن تصدر ES7، بل بإمكاننا إيجاد حلّ وسط لهذه المشكلة؛ لماذا نضطّر إلى تعقيد الأمور بالاستدعاءات الرّاجعة المتداخلة؟ ألا يتوفّر في اللّغة بنية برمجيّة تسمح بإيقاف شيفرتنا ريثما يتمّ أمر ما غير متزامن (<strong>الانتظار</strong> لإكمال طلب AJAX) ثمّ <strong>المتابعة</strong> بعد انتهاءه؟ يبدو هذا الحديث مألوفًا!</p><p>نعلم حتى الآن أننا بحاجة لاستخدام مولّد، ولذلك سنحيط شيفرتنا بدالّة مولّد كخطوة أولى:</p><pre class="javascript ipsCode prettyprint">var list = document.querySelector("#book-list");

function* displayUserProfile() {
    // شيفرتنا هنا
}

الآن نحتاج لتنفيذ طلب AJAX الأوّل والانتظار إلى انتهاءه قبل الانتقال إلى الطّلب الثّاني، نعلم أنّ yield توقف تنفيذ المولّد:


var list = document.querySelector("#book-list");

function* displayUserProfile() {
    yield getJSON("http://reading-website.com/users/fwz.json");
    // ...
}
</pre><p> </p><p>عظيم! لكن كيف نُخبر المولّد بأنّ عليه متابعة التنفيذ؟</p><pre class="javascript ipsCode prettyprint">var list = document.querySelector("#book-list");

function* displayUserProfile() {
    yield getJSON("http://reading-website.com/users/fwz.json", resume);
    // ...
}

سنمرر دالة اسمها resume للدّالة getJSON، وهذه الدالة ستُستدعى عند انتهاء جلب جواب الطّلب الذي أرسلناه، وهي فرصتنا لإخبار المولّد بمتابعة التنفيذ... فكيف سيكون محتواها؟

var list = document.querySelector("#book-list");

var resume = function(err, response) {
     displayIterator.next(response);
}

function* displayUserProfile() {
    var user = yield getJSON("http://reading-website.com/users/fwz.json", resume);
    var num_books = user.books.length;
    var most_recent_book_id = user.books[num_books - 1];

    var user_rating = yield getJSON("http://reading-website.com/users/fwz/ratings/" + most_recent_book_id + ".json", resume);
    var book = yield getJSON("http://reading-website.com/books/" + most_recent_book_id + ".json", resume);

    var fragment = document.createDocumentFragment();

    var h2 = document.createElement("h2");
    h2.innerText = user.full_name;

    var h3 = document.createElement("h3");
    h3.innerText = "الكتب التي قرأها";

    for (let book of books) {
        let li = document.createElement("li");
        li.innerText = book.title + (book.id == most_recent_book_id ? " " + user_rating : "");
        fragment.appendChild(li);
    }

    list.appendChild(fragment);
}

var displayIterator = displayUserProfile();
displayIterator.next();
</pre><p>حفظنا نسخة عن المكرّر في متغيّر ثم استدعينا وظيفته <code>next()</code> في دالّة المتابعة، ممرّرين لها جواب الطّلب ليمكننا تخزينه ضمن المتغيّر <code>user</code>. الدّالة resume تستطيع الوصول إلى <code>displayIterator</code> لأنّه يكون معرّفًا قبل استدعاءها حتمًا، ولا ننسَ أن تعريف المتغيّرات في JavaScript يخضع لعملية <a rel="external nofollow" href="http://www.w3schools.com/js/js_hoisting.asp">الرّفع إلى أعلى النّطاق (variable hoisting)</a> ممّا يجعل المتغيّر <code>displayIterator</code> موجودًا (وإن كان بلا قيمة) منذ بداية تنفيذ الشيفرة.</p><p>للتأكّد من فهم هذه الشيفرة، سنعيد تحليلها خطوة بخطوة: في طلب AJAX الأوّل تستدعى الدالة <code>resume</code> ويمرّر إليها جواب الطّلب (<code>response</code>)، الذي يمرّر بدوره إلى المُكرّر ليُحفظ في المتغيّر <code>user</code> الذي سيُستخدم في الخطوة التّالية للمولّد لإرسال الطّلب الثّاني. تُكرّر العمليّة ذاتها للطلبين الآخرين ثمّ تُعرض النتائج في الصّفحة. الفائدة التي جنيناها من استخدام المولّدات هي التخلّص من تعقيد الاستدعاءات الرّاجعة نهائيًّا وتحويل شيفرة غير متزامنة وجعلها تبدو وكأنّها متزامنة. ذكرنا القليل عن مكتبات مثل co وsuspend، لكنّها باختصار تعمل بطريقة مماثلة جدًا لمثالنا الأخير:</p><pre class="javascript ipsCode prettyprint">var suspend = require('suspend'),
    resume = suspend.resume;

suspend(function*() {
    var data = yield fs.readFile(__filename, 'utf8', resume());
    console.log(data);
})();</pre><p>هذه المكتبات خطوة نحو مستقبل JavaScript، الذي بدأ يتشكل مع مشروع الدّوال غير المتزامنة باستخدام الكلمتين المفتاحيتين الجديدتين <code>async</code> و<code>await</code> اللّتان ستتوفّران في الإصدار السّابع وتستندان في عملهما إلى أرضيّة الوعود (Promises) الّتي تتوفّر اليوم في ES6. سيكون بإمكاننا كتابة هذه الشيفرة بدل الاعتماد على المولّدات:</p><pre class="javascript ipsCode prettyprint">async function displayUserProfile() {
   var user = await getJSON("http://reading-website.com/users/fwz.json");

   var num_books = user.books.length;
   var most_recent_book_id = user.books[num_books - 1];

   var user_rating = await getJSON("http://reading-website.com/users/fwz/ratings/" + most_recent_book_id + ".json");
   var book = await getJSON("http://reading-website.com/books/" + most_recent_book_id + ".json");

   var fragment = document.createDocumentFragment();

   var h2 = document.createElement("h2");
   h2.innerText = user.full_name;

   var h3 = document.createElement("h2");
   h2.innerText = "الكتب التي قرأها";

   for (let book of books) {
       let li = document.createElement("li");
       li.innerText = book.title + (book.id == most_recent_book_id ? " " + user_rating : "");
       fragment.appendChild(li);
   }

   list.appendChild(fragment);
}</pre><p>في هذا المثال يجب على <code>getJSON</code> أن تُعيد وعدًا <code>Promise</code> ليستطيع مُفسّر اللّغة انتظاره إلى أن يُحقّق (resolve) أو يُرفض (reject)، والقيمة الّتي تُحقّق تُحفظ ضمن المُتغيّر <code>user</code>، وأما عند رفض الوعد يُرمى خطأ (<code>throw</code>) يمكن تلقّيه (<code>catch</code>) كما في الشيفرة غير المتزامنة.</p><h2>مُعامِل البقيّة (Rest parameter) والناشرة (Spread)</h2><p>بعد كلّ هذا الكلام المُعقّد عن الأشياء غير المتزامنة التي نريد جعلها تبدو متزامنة وما إلى ذلك، سنختم الجزء الثّاني بفكرتين بسيطتين أُضيفتا إلى ECMAScript في الإصدار السّادس وتحلّان مشكلتين شائعتين في كثير من اللّغات البرمجيّة:</p><p>أمّا الأولى فهي الحاجة إلى تنفيذ نصّ برمجيّ ضمن دالة على عدد غير معروف من المُعاملات، فلنفترض أنّ لدينا دالة تجمع عددين:</p><pre class="javascript ipsCode prettyprint">function add(n1, n2) {
    return n1 + n2;
}

add(1)
// 1
add(1, 2)
// 3</pre><p>ونظرًا لكوننا مبرمجين أذكياء فقد قرّرنا جعل الدّالة تقبل أي عددين أو ثلاثة أو أكثر... لنجعلها تقبل عددًا لا نهائيًّا من الأعداد؛ في الإصدار الحالي سنلجأ إلى استخدام الكائن الخاصّ <code>arguments</code> المتوفّر ضمن نطاق كلّ دالّة تلقائيًا:<code class="lang-javascript"> </code></p><pre class="javascript ipsCode prettyprint">function add() {
   return [].reduce.call(arguments, function(memo, n) { return memo + n; });
}

add(1)
// 1
add(1, 2)
// 3
add(1, 2, 3)
// 6
</pre><p>حسنًا لقد اضطررنا إلى "استعارة" دالة الاختزال من مصفوفة فارغة لتطبيقها على الكائن الخاص <code>arguments</code> الذي يُعتبر "شبيه مصفوفة" ولا يملك ما تمتلكه المصفوفة من دوالّ، لماذا لا يمكننا كتابة هذا فحسب:<code class="lang-javascript"> </code></p><pre class="javascript ipsCode prettyprint">function add(...numbers) {
    return numbers.reduce(function(memo, n) { return memo + n; });
}

add(1)
// 1
add(1, 2)
// 3
add(1, 2, 3)
// 6
</pre><p>وأمّا الفكرة الثّانية فهي تكاد تكون عكس السّابقة، فإذا كانت الأولى تجمع بقيّة المعاملات في كائن مُفرَد، فإنّ هذه "تَنشر" محتويات المصفوفة إلى عناصرها المكوّنة لها، ماذا لو لم نكن أذكياء وعجزنا عن الإتيان بدالة تجمع عددًا غير منتهٍ من الأرقام:<code class="lang-javascript"> </code></p><pre class="javascript ipsCode prettyprint">function addThreeNumbers(n1, n2, n3) {
     return n1 + n2 + n3;
}

var myNumbers = [1, 2, 3];
addThreeNumbers(...myNumbers);

// 6
</pre><p>لاحظ أن صياغة النشر (Spread) تطابق تمامًا صياغة البقيّة (Rest)، والاختلاف في السّياق فقط. لاحظ أيضًا أنّ معامل البقيّة، وكما يوحي اسمه، يمكن استخدامه لتجميع <em>ما تبقى</em> من مُعاملات الدّالة فقط:</p><pre class="javascript ipsCode prettyprint">function addThreeOrMoreNumbers(n1, n2, ...numbers) {
    return n1 + n2 + numbers.reduce(function(memo, n) { return memo + n; });
}

addThreeOrMoreNumbers(1, 2, 3);
// 6</pre><p>في الجزء القادم سنتعرف بمشيئة الله على الوحدات (Modules) التي تُعتبر طريقة جديدة لتنظيم الشفرة اُستلهمَت من عالم Node.js وrequire.js، وسُنلقي نظرة على الأصناف (Classes)، المكوّن البرمجيّ الذي وجد طريقه أخيرًا إلى JavaScriptّ!</p><h3>المصادر</h3><ol><li><a rel="external nofollow" href="https://developer.mozilla.org">شبكة مطوّري موزيلّا</a></li><li><a rel="external nofollow" href="http://davidwalsh.name/async-generators">Going Async With ES6 Generators</a></li><li><a rel="external nofollow" href="http://modernweb.com/2014/02/10/replacing-callbacks-with-es6-generators">Replacing callbacks with ES6 Generators </a></li><li><a rel="external nofollow" href="http://jakearchibald.com/2014/iterators-gonna-iterate/">Iterators gonna iterate</a></li></ol>]]></description><guid isPermaLink="false">26</guid><pubDate>Tue, 03 Mar 2015 19:10:23 +0000</pubDate></item><item><title>&#x643;&#x62A;&#x627;&#x628;&#x629; JavaScript &#x64A;&#x633;&#x647;&#x644; &#x627;&#x62E;&#x62A;&#x628;&#x627;&#x631;&#x647;&#x627;</title><link>https://academy.hsoub.com/programming/javascript/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-javascript-%D9%8A%D8%B3%D9%87%D9%84-%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D9%87%D8%A7-r18/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_03/js_480x300.jpg.050c808dce831d2625fb2f6f5e2e2828.jpg" /></p>

<p>مررنا جميعًا بموقف كهذا: بضع سطور JavaScript كُتبت لتؤدّي وظيفة صغيرة ثمّ تضخمت مع الوقت لتبلغ بضع عشرات من السطور، ثم مئات السطور... أصبحت تقبل معاملات أكثر، وتختبر شروطًا أكثر، ثم أتى ذلك اليوم: تقرير بعلّة، التطبيق لا يعمل كما ينبغي! وحينئذ يكون فكّ غموض هذه السطور المتشابكة مسؤوليّتنا.</p><p>مع تزايد الأعباء الّتي نُلقيها على مشروعنا من جهة المتصفّح، يتّضح أمامنا أمران: أوّلهما: تجربة التطبيق بالنقر على الأزرار والروابط سريعًا ليس حلًّا عمليًّا، بل لا بدّ من الاختبارات المُؤتمتة حتّى نثق باستقرار مشروعنا؛ وثانيهما: علينا (غالبًا) أن نُغيّر كيفيّة كتابة برامجنا بما يُتيح لنا كتابة الاختبارات.</p><p>هل أنا جادّة؟ نعم! لأنّنا وإن علمنا فائدة الاختبارات المؤتمتة، فإنّ أكثرنا اليوم لا يكتبون سوى اختبارات التكامل (integration tests). لا يُقلّل هذا من أهمّيّة اختبارات التكامل، فهي تُركّز على كيفيّة عمل أجزاء التّطبيق سويّةً، إلّا أنّها لا تستطيع إخبارنا إن كانت <em>الوحدات</em> المنفصلة لتطبيقنا تعمل كما ينبغي لها.</p><p>هنا تبرز ضرورة اختبارات الوحدات (unit tests)، وستكون <em>كتابة اختبارات الوحدات</em> صعبة جدًّا إن لم يكن <em>نصّ JavaScript الّذي كتبناه ملائمًا للاختبار</em>.</p><h2>ما الفرق بين اختبارات الوحدات واختبارات التكامل؟</h2><p>كتابة اختبارات التكامل أمر بسيط عادةً: كل ما نفعله كتابة برنامج بسيط يصف كيف يتفاعل المُستخدم مع تطبيقنا، وما يجب أن يتوقّعه المستخدم عندئذٍ. إحدى برامج أتمتة المُتصفّحات الشّهيرة <a rel="external nofollow" href="http://docs.seleniumhq.org">Selenium‏</a>. وفي Ruby يُسهل <a rel="external nofollow" href="https://github.com/jnicklas/capybara">Capybara‏</a> التّعامل مع Selenium، وتتوفّر أدوات مشابهة كثيرة للغات الأخرى.</p><p>فيما يلي اختبار تكامل لجزء من تطبيق بحث:<code class="lang-ruby"> </code></p><pre class="html ipsCode prettyprint">def test_search
  fill_in('q', :with =&gt; 'cat')
  find('.btn').click
  assert( find('#results li').has_content?('cat'), 'Search results are shown' )
  assert( page.has_no_selector?('#results li.no-results'), 'No results is not shown' )
end
</pre><p>إذن فاختبار التكامل يهتمّ بتفاعل المستخدم مع التّطبيق، أمّا اختبار الوحدات فتركيزه ضيّق ويقتصر على جزء صغير من البرنامج:</p><blockquote><p>عندما أستدعي دالّةً (function) بمُدخلات معيّنة، فما المُخرجات المُتوقّعة؟</p></blockquote><p>يصبح إخضاع التّطبيقات المكتوبة بأسلوب إجرائي (procedural) تقليديّ لاختبار الوحدات أمرًا شديد الصعوبة، وكذلك صيانتها وتنقيحها والبناء عليها. ولكن عندما نكتب نصوص برامجنا وفي ذهننا الحاجة لإجراء اختبارات الوحدات في المستقبل، فسنجد أنّ كتابة هذه الاختبارات أمر يسير، وسينعكس ذلك بالإيجاب على نصوصنا البرمجية كذلك.</p><p>لنفهم ما أتحدّث عنه، دعنا نُلقِ نظرةً على تطبيق بحث بسيط:</p><p href="https://academy.hsoub.com/uploads/monthly_2015_03/app.png.b36a77166bd57c1f7878033a878a52a7.png"><img class="ipsImage ipsImage_thumbnailed" data-fileid="24" alt="app.png.b36a77166bd57c1f7878033a878a52a7" src="https://academy.hsoub.com/uploads/monthly_2015_03/app.thumb.png.aee5b446365a49a254e60f3878e9be1b.png"></p><p>عندما يكتب المستخدم عبارة للبحث عنها، يُرسل التّطبيق طلب <code>XMLHttpRequest</code> للخادوم يطلب منه البيانات المُوافقة. يُجيبه الخادوم بالبيانات، مُصاغاة بـJSON، ليتلقّاها التطبيق ويعرضها في الصّفحة مُستخدمًا أدوات القولبة المُتوفّرة للمتصفّحات. يستطيع المستخدم أن ينقر على إحدى نتائج البحث ليُشير "بإعجابه" بها؛ وعندما يفعل ذلك، يُضاف اسم الشّخص الّذي أعجبه إلى قائمة "الإعجابات" على يمين الصّفحة.</p><p>يمكن كتابة هذا البرنامج بأسلوب تقليدي كما يلي:</p><pre class="javascript ipsCode prettyprint">var tmplCache = {};

function loadTemplate (name) {
  if (!tmplCache[name]) {
    tmplCache[name] = $.get('/templates/' + name);
  }
  return tmplCache[name];
}

$(function () {

  var resultsList = $('#results');
  var liked = $('#liked');
  var pending = false;

  $('#searchForm').on('submit', function (e) {
    e.preventDefault();

    if (pending) { return; }

    var form = $(this);
    var query = $.trim( form.find('input[name="q"]').val() );

    if (!query) { return; }

    pending = true;

    $.ajax('/data/search.json', {
      data : { q: query },
      dataType : 'json',
      success : function (data) {
        loadTemplate('people-detailed.tmpl').then(function (t) {
          var tmpl = _.template(t);
          resultsList.html( tmpl({ people : data.results }) );
          pending = false;
        });
      }
    });

    $('&lt;li&gt;', {
      'class' : 'pending',
      html : 'Searching &amp;hellip;'
    }).appendTo( resultsList.empty() );
  });

  resultsList.on('click', '.like', function (e) {
    e.preventDefault();
    var name = $(this).closest('li').find('h2').text();
    liked.find('.no-results').remove();
    $('&lt;li&gt;', { text: name }).appendTo(liked);
  });

});
</pre><p>يحلو لصديقنا <a rel="external nofollow" href="https://twitter.com/ajpiano">Adam Sontag‏</a> أن يُسمّي هذا الأسلوب <em>"اختر مغامرتك الخاصّة"</em>، ويحقّ له ذلك! ففي أيّ سطر ممّا سبق، قد نتعامل مع كيفيّة عرض البيانات، أو مع البيانات ذاتها، أو مع تفاعل المستخدم مع الصّفحة، أو مع حالة التّطبيق في لحظة معيّنة! من يدري!؟ هذا الأسلوب لا يجعل كتابة اختبارات التكامل صعبًا، ولكنّ اختبار المهامّ المختلفة للبرنامج تصبح معه غايةً في التعقيد.</p><p>كيف ذلك؟ لنرَ:</p><ul><li>غياب كامل لبنية واضحة؛ فكلّ شيء يحدث ضمن <code>‎$(document).ready()‎</code> ثمّ في دوالّ مجهولة لا يمكن اختبارها لأنّها مُغلّفة ضمن الدّالة السّابقة ولا يمكن الوصول إليها.</li><li>دوالّ معقدة؛ فعندما تتجاوز دالّة مُفردة 10 سطور، كما في دالّة إرسال النّموذج، فهذا يعني غالبًا أنّها تفعل أشياء أكثر مما ينبغي لها أن تفعل!</li><li>حالة (state) مخفيّة أو مُشتركة؛ كالمتغيّر <code>pending</code> المُعرّف ضمن دالّة مُغلقة (closure)، لا سبيل لاختبار قيمته والتأكّد من كونها عُينت إلى قيمة صحيحة في لحظة ما.</li><li>اعتماد شديد للأجزاء بعضها على بعض؛ فمثلاً: لا تحتاج دالّة نجاح طلب <code>‎$.ajax</code> وصولًا مباشرًا إلى عناصر الصّفحة.</li></ul><h2>تنظيم النّصّ البرمجيّ</h2><p>الخطوة الأولى لحلّ المشكلة السابقة هي إزالة هذا التّشابك، وفصل المهامّ السابقة إلى عدّة أجزاء:</p><ul><li>العرض والتفاعل</li><li>إدارة البيانات وتخزينها</li><li>حالة التطبيق العامّة</li><li>ربط الأجزاء السّابقة مع بعضها لتعمل سويّةً!</li></ul><p>في الأسلوب التّقليديّ الّذي بيّناه سابقًا، تتشابك هذه المهمّات الأربع، ففي سطرٍ نتعامل مع العرض، وبعده ببضع سطور نتواصل مع الخادوم.</p><p href="https://academy.hsoub.com/uploads/monthly_2015_03/code-lines.png.a0e492ba2e18a0ca9069d30e8208579d.png"><img class="ipsImage ipsImage_thumbnailed" data-fileid="26" alt="code-lines.png.a0e492ba2e18a0ca9069d30e8" src="https://academy.hsoub.com/uploads/monthly_2015_03/code-lines.thumb.png.947ac2f5468d78ecec2f2978def2f432.png"></p><p>يمكننا كتابة اختبار تكامل للبرنامج السابق بلا شكّ (بل ينبغي أن نفعل!)، ولكن كتابة اختبارات الوحدات أمرٌ صعب. في اختبارات التكامل، يمكننا افتراض عبارات من نحو "عندما يبحث المستخدم عن شيءٍ ما، يُتوقّع أن يرى النّتائج المُناسبة"، ولكن لا يمكننا التعمّق في التّفاصيل، وإن حدثت مشكلةٌ ما، ينبغي علينا تحديد موقع المشكلة بالضّبط، ولن تساعدنا اختبارات التكامل في ذلك.</p><p>ولكنْ، إن أعدنا التفكير في كيفيّة كتابة نصّ البرنامج يمكننا كتابة اختبارات للوحدات تُسهِّل لنا تحديد موقع المشكلة، وتسمح بتسهيل صيانة النّصّ النهائي للبرنامج وتحسينه واستخدامه ثانيةً.</p><p>سيتَّبع برنامجنا الجديد المبادئ التّالية:</p><ul><li>مثّل كلّ مهمّة ضمن كائن مُنفصل يقع تنصيفه في واحدة من المناطق الأربعة الّتي سبق ذكرها، دون أن يكون هذا الكائن في حاجة لمعرفة وجود الكائنات الأخرى. هذا يُجنّنبا تشابك النّص البرمجيّ.</li><li>ادعم إمكانية الضّبط، بدلًا من كتابة قيم ثابتة. هذا سيُجنّبنا الحاجة لمحاكاة كامل بيئة HTML عند إجراء الاختبارات.</li><li>أبقِ وظائف الكائنات بسيطة ومُوجزة. سيؤدّي هذا إلى نصّ برمجيّ أبسط وأسهل قراءةً.</li><li>استخدم دوالّ مُشيّدة (constructors) لإنشاء نسخ من الكائنات، هذا يُتيح إنشاء نُسخ "نظيفة" من كلّ جزء من البرنامج لغرض الاختبار.</li></ul><p>بدايةً، علينا أن نكتشف كيف سنفصل تطبيقنا لعدّة أجزاء. سيكون لدينا 3 أجزاء مُخصّصة للعرض والتفاعل: نموذج البحث ونتائج البحث ومساحة الإعجابات.</p><p href="https://academy.hsoub.com/uploads/monthly_2015_03/app-views.png.5afd37ed19bd188c4c99d204989c7d82.png"><img class="ipsImage ipsImage_thumbnailed" data-fileid="25" alt="app-views.png.5afd37ed19bd188c4c99d20498" src="https://academy.hsoub.com/uploads/monthly_2015_03/app-views.thumb.png.126b75673fa547a3e19bb31fdb04a684.png"></p><p>سيكون لدينا أيضًا جزء مُخصّص لجلب البيانات من الخادوم، وجزء آخر يربط بين تلك الأجزاء كلها.</p><p>لنبدأ بالنّظر في واحد من أبسط أجزاء التطبيق: مساحة الإعجابات. في الإصدار السّابق من برنامجنا، كان النّصّ التّالي مسؤولًا عن تحديث هذه المساحة:</p><pre class="javascript ipsCode prettyprint">var liked = $('#liked');

var resultsList = $('#results');


// ...


resultsList.on('click', '.like', function (e) {
  e.preventDefault();

  var name = $(this).closest('li').find('h2').text();

  liked.find( '.no-results' ).remove();

  $('&lt;li&gt;', { text: name }).appendTo(liked);

});</pre><p>لاحظ كيف يتداخل جزء نتائج البحث في جزء مساحة الإعجابات وكيف يحتاج أن يعلم الكثير عن عناصره في الصّفحة. إن أردنا كتابة هذا الجزء بأسلوب أسهل اختبارًا، فعلينا إنشاء كائن لمساحة الإعجابات مسؤولٍ عن تعديل عناصر الصّفحة المُتعلّقة بقائمة الإعجابات:</p><pre class="javascript ipsCode prettyprint">var Likes = function (el) {
  this.el = $(el);
  return this;
};

Likes.prototype.add = function (name) {
  this.el.find('.no-results').remove();
  $('&lt;li&gt;', { text: name }).appendTo(this.el);
};
</pre><p>يوفّر هذا النّصّ دالّة تشييد (constructor function) تُعطي نسخة جديدة من مساحة الإعجابات. للنسخة المُنشأة وظيفة <code>.add()‎</code> يمكن استخدامها لإضافة نتائج جديدة. ولإثبات صحّة عملها، يمكننا كتابة بضعة اختبارات:</p><pre class="javascript ipsCode prettyprint">var ul;

setup(function(){
  ul = $('&lt;ul&gt;&lt;li class="no-results"&gt;&lt;/li&gt;&lt;/ul&gt;');
});

test('constructor', function () {
  var l = new Likes(ul);
  assert(l);
});

test('adding a name', function () {
  var l = new Likes(ul);
  l.add('Brendan Eich');

  assert.equal(ul.find('li').length, 1);
  assert.equal(ul.find('li').first().html(), 'Brendan Eich');
  assert.equal(ul.find('li.no-results').length, 0);
});</pre><p>ليس الأمر صعبًا كما ترى! استخدمنا <a rel="external nofollow" href="http://visionmedia.github.io/mocha">Mocha‏</a> كإطار عمل للاختبار و<a rel="external nofollow" href="http://chaijs.com">Chai‏</a> كمكتبة لإنشاء الافتراضات (assesrtions). ‏Mocha توفّر <code>test</code> و<code>setup</code>، وChai توفّر <code>assert</code>. تتوفّر أطر عمل ومكتبات للافتراضات كثيرة، ولكنّ السابقتين ملائمتان تمامًا للمُبتدئين. عليك اختيار ما يناسبك ويناسب مشروعك. اطّلع على <a rel="external nofollow" href="http://qunitjs.com">QUnit‎‏</a> و<a rel="external nofollow" href="http://theintern.io">Intern‎‏</a> (الأخيرة تبدو واعدة).</p><p>يبدأ برنامج الاختبا بإنشاء عنصر في الصّفحة سنستخدمه لاحتواء مساحة الإعجابات، ثمّ ينطلق اختباران: الأول للتأكّد من إمكانيّة إنشاء مساحة الإعجابات، والآخر للتأكد من أن وظيفة <code>.add()‎</code> تعطينا النتيجة المرغوبة. بعد إنشاء هذين الاختبارين، يمكننا إعادة صياغة النصّ البرمجي لمساحة الإعجابات، مطمئنين إلى أنّ الأخطاء الّتي نرتكبها عندئذٍ ستُكتشف فورًا في الاختبار.</p><p>يبدو تطبيقنا الآن كما يلي:</p><pre class="javascript ipsCode prettyprint">var liked = new Likes('#liked');
var resultsList = $('#results');



// ...



resultsList.on('click', '.like', function (e) {
  e.preventDefault();

  var name = $(this).closest('li').find('h2').text();

  liked.add(name);
});</pre><p>جزء نتائج البحث أشدّ تعقيدًا من مساحة الإعجابات، لكن لنجرّب إعادة صياغته أيضًا. نريد أن نُنشئ وظائف للتفاعل مع نتائج البحث كما أنشأنا الوظيفة <code>.add()‎</code> لمساحة الإعجابات. نريد طريقةً لإضافة نتائج جديدة، وكذلك طريقة "لبثّ" التّغيرات الّتي تطرأ على النّتائج لبقيّة أجزا التّطبيق (كأن يُعجب المستخدم بنتيجة مثلاً).</p><pre class="javascript ipsCode prettyprint">var SearchResults = function (el) {
  this.el = $(el);
  this.el.on( 'click', '.btn.like', _.bind(this._handleClick, this) );
};

SearchResults.prototype.setResults = function (results) {
  var templateRequest = $.get('people-detailed.tmpl');
  templateRequest.then( _.bind(this._populate, this, results) );
};

SearchResults.prototype._handleClick = function (evt) {
  var name = $(evt.target).closest('li.result').attr('data-name');
  $(document).trigger('like', [ name ]);
};

SearchResults.prototype._populate = function (results, tmpl) {
  var html = _.template(tmpl, { people: results });
  this.el.html(html);
};</pre><p>الآن يمكن لنصّنا البرمجيّ القديم المسؤول عن إدارة التفاعلات بين نتائج البحث ومساحة الإعجابات أن يصبح كما يلي:</p><pre class="javascript ipsCode prettyprint">var liked = new Likes('#liked');
var resultsList = new SearchResults('#results');


// ...


$(document).on('like', function (evt, name) {
  liked.add(name);
})</pre><p>وهذا أبسط وأقل تشابكًا، لأنّنا نستخدم <code>document</code> كممرّ عامّ للرّسائل المُتبادلة بين الأجزاء بحيث لا يضطرّ أحدها إلى أن يعلم وجود الآخر. (ملاحظة: في تطبيق حقيقيّ، ربّما يُستخدم شيء مثل <a rel="external nofollow" href="http://backbonejs.org">Backbone‏</a> أو مكتبة <a rel="external nofollow" href="https://github.com/tildeio/rsvp.js">RSVP‏</a> لإدارة الأحداث، استخدمنا <code>document</code> للتبسيط.) كذلك أخفينا كل التّفاصيل المُعفّدة (كإيجاد اسم الشّخص الّذي أُعجب المستخدم به) داخل كائن نتائج البحث، بدل أن نترك هذه التّفاصيل تُلوّث نصّ تطبيقنا. أفضل ما في الأمر هو أنّ بإمكاننا الآن كتابة اختبارات للتأكّد من عمل كائن نتائج البحث كما يجب:</p><pre class="javascript ipsCode prettyprint">var ul;
var data = [ /* fake data here */ ];

setup(function () {
  ul = $('&lt;ul&gt;&lt;li class="no-results"&gt;&lt;/li&gt;&lt;/ul&gt;');
});

test('constructor', function () {
  var sr = new SearchResults(ul);
  assert(sr);
});

test('display received results', function () {
  var sr = new SearchResults(ul);
  sr.setResults(data);

  assert.equal(ul.find('.no-results').length, 0);
  assert.equal(ul.find('li.result').length, data.length);
  assert.equal(
    ul.find('li.result').first().attr('data-name'),
    data[0].name
  );
});

test('announce likes', function() {
  var sr = new SearchResults(ul);
  var flag;
  var spy = function () {
    flag = [].slice.call(arguments);
  };

  sr.setResults(data);
  $(document).on('like', spy);

  ul.find('li').first().find('.like.btn').click();

  assert(flag, 'event handler called');
  assert.equal(flag[1], data[0].name, 'event handler receives data' );
});</pre><p>التفاعل مع الخادم جزء آخر يجب إنشاؤه، وقد احتوى النّص البرمجيّ القديم على طلب <code>‎$.ajax()‎</code> فيه استدعاء راجع (callback) يتعامل مباشرةً مع عناصر الصّفحة:</p><pre class="javascript ipsCode prettyprint">$.ajax('/data/search.json', {
  data : { q: query },
  dataType : 'json',
  success : function( data ) {
    loadTemplate('people-detailed.tmpl').then(function(t) {
      var tmpl = _.template( t );
      resultsList.html( tmpl({ people : data.results }) );
      pending = false;
    });
  }
});
</pre><p>مُجدّدًا أقول: من الصعب كتابة اختبار وحدات للنّصّ السابق لأن أشياء كثيرةً تحدث في بضع سطور. يمكننا إعادة صياغة القسم المسؤول عن البيانات في صورة كائن مُنفصل:</p><pre class="javascript ipsCode prettyprint">var SearchData = function () { };

SearchData.prototype.fetch = function (query) {
  var dfd;

  if (!query) {
    dfd = $.Deferred();
    dfd.resolve([]);
    return dfd.promise();
  }

  return $.ajax( '/data/search.json', {
    data : { q: query },
    dataType : 'json'
  }).pipe(function( resp ) {
    return resp.results;
  });
};</pre><p>وعندها يمكن تعديل النّصّ البرمجيّ لجلب النّتائج إلى الصّفحة:</p><pre class="javascript ipsCode prettyprint">var resultsList = new SearchResults('#results');

var searchData = new SearchData();

// ...

searchData.fetch(query).then(resultsList.setResults);
</pre><p>لاحظ كم بسّطنا نصّ تطبيقنا، وكيف عزلنا التّعقيدات ضمن كائن بيانات البحث، بدلًا من تركه حُرًّا ضمن نصّ تطبيقنا العامّ. قمنا أيضًا بجعل واجهة البحث قابلةً للاختبار. ولكن هناك بضعة أمور يجب النّظر فيها عندما نختبر جزءًا من برنامج يتفاعل مع الخواديم.</p><p>أوّل هذه الأمور: لا نريد أنّ نتفاعل مع الخادوم <em>حقيقةً</em>، ففعل ذلك يعني العودة إلى عالم اختبارات التّكامل، ولأنّنا مُطوّرون أكفاء، فقد انتهينا من كتابة تلك، صحيح؟ ما نريده الآن هو "محاكاة" التّفاعل مع الخادوم، الأمر الّذي يمكن إنجازه بمكتبة <a rel="external nofollow" href="http://sinonjs.org/">Sinon‏</a>. ثانيًا: يجب أيضًا اختبار المسارات غير المُتوقّعة للتطبيق، كعبارة بحث فارغة مثلًا.</p><pre class="javascript ipsCode prettyprint">&lt;code class="lang-javascript"&gt;
&lt;/code&gt;test('constructor', function () {
  var sd = new SearchData();
  assert(sd);
});

suite('fetch', function () {
  var xhr, requests;

  setup(function () {
    requests = [];
    xhr = sinon.useFakeXMLHttpRequest();
    xhr.onCreate = function (req) {
      requests.push(req);
    };
  });

  teardown(function () {
    xhr.restore();
  });

  test('fetches from correct URL', function () {
    var sd = new SearchData();
    sd.fetch('cat');

    assert.equal(requests[0].url, '/data/search.json?q=cat');
  });

  test('returns a promise', function () {
    var sd = new SearchData();
    var req = sd.fetch('cat');

    assert.isFunction(req.then);
  });

  test('no request if no query', function () {
    var sd = new SearchData();
    var req = sd.fetch();
    assert.equal(requests.length, 0);
  });

  test('return a promise even if no query', function () {
    var sd = new SearchData();
    var req = sd.fetch();

    assert.isFunction( req.then );
  });

  test('no query promise resolves with empty array', function () {
    var sd = new SearchData();
    var req = sd.fetch();
    var spy = sinon.spy();

    req.then(spy);

    assert.deepEqual(spy.args[0][0], []);
  });

  test('returns contents of results property of the response', function () {
    var sd = new SearchData();
    var req = sd.fetch('cat');
    var spy = sinon.spy();

    requests[0].respond(
      200, { 'Content-type': 'text/json' },
      JSON.stringify({ results: [ 1, 2, 3 ] })
    );

    req.then(spy);

    assert.deepEqual(spy.args[0][0], [ 1, 2, 3 ]);
  });
});</pre><p>سأترك ما تبقّى من إعادة صياغة نموذج البحث لغرض الاختصار، وقد قمت بتبسيط بعض الاختبارات والنّصوص أعلاه مُجدّدًا، ويمكنك الاطّلاع على الإصدار النّهائي للتطبيق <a rel="external nofollow" href="https://github.com/rmurphey/testable-javascript">هنا</a> إن كنت مُهتمًّا.</p><p>عندما ننتهي من كتابة تطبيقنا بأسلوب يسمح بإجراء الاختبارات، سيكون مشروعنًا أكثر نظافةً ممّا بدأنا به:<code class="lang-javascript"> </code></p><pre class="javascript ipsCode prettyprint">$(function() {
  var pending = false;

  var searchForm = new SearchForm('#searchForm');
  var searchResults = new SearchResults('#results');
  var likes = new Likes('#liked');
  var searchData = new SearchData();

  $(document).on('search', function (event, query) {
    if (pending) { return; }

    pending = true;

    searchData.fetch(query).then(function (results) {
      searchResults.setResults(results);
      pending = false;
    });

    searchResults.pending();
  });

  $(document).on('like', function (evt, name) {
    likes.add(name);
  });
});
</pre><p>والأهمّ من ذلك أنّنا ننتهي ولدينا مشروعٌ أُخضع لاختبارات دقيقة، وهذا يعني أنّ بإمكاننا إعادة كتابة الأجزاء ونحن مطمئنون إلى أنّ ذلك لن يسيئ إلى عمل التطبيق. بإمكاننا أيضًا إضافة اختبارات جديدةً عندما نكتشف مشكلات جديدة، ثمّ كتابة النّصّ الّذي يجعل هذه الاختبار تنجح.</p><h2>اختبار البرامج يُسهّل حياتك على المدى البعيد</h2><p>من السهولة أن تنظر إلى ما سبق وتقول لنفسك: "مهلًا! أتريدين منّي كتابة برامج أطول لأداء المهمّة ذاتها؟"</p><p>عندما يتعلّق الأمر ببناء المشاريع على الإنترنت، فإنّه لا مفرّ من هذه الحقيقة: لا بدّ من وقتٍ كافٍ لتصميم منهجٍ لحلّ مشكلة. لا بدّ من تجربة الحلّ، سواءٌ كانت التّجربة يدويّة تقوم بها بنفسك في المتصفّح، أو مؤتمتة، أو أن تترك مستخدميك يجرّبوا مشروعك بعد نشره (فكرة مرعبة!). ستُغيّر نصوصك البرمجيّة، ثمّ سيستخدمها آخرون، وفي النّهاية ستبقى العلل موجودة مهما بلغ عدد الاختبارات الّتي تكتبها.</p><p>صحيحٌ أنّ الاختبارات تتطلّب وقتًا عند كتابتها أوّل مرّة، ولكنّها ستوفّر وقتك في المدى البعيد، سترضى عن نفسك عندما يفشل أحد الاختبارات الّتي كتبتها كاشفًا عن علّة قبل أن يصل النّص البرمجيّ إلى مرحلة الإنتاج، وكذلك عندما يكون لديك نظامٌ يُثبت أنّ العلل قد حلّت بالفعل قبل أن تجد طريقها إلى المُستخدمين!</p><h2>مصادر إضافيّة</h2><p>كلّ ما كتبته أعلاه ليس إلّا أقلّ القليل من موضوع اختبارات JavaScript، فإن أردت المزيد:</p><ul><li>شاهد <a rel="external nofollow" href="http://lanyrd.com/2012/full-frontal/sztqh">العرض</a> الذي قدّمته في مؤتمر Full Frontal عام 2012 في برايتون في المملكة المتحدة.</li><li>أو جرّب <a rel="external nofollow" href="http://gruntjs.com/">Grunt‏</a>، وهي أداة تُساعدك في أتمتة عمليّة الاختبارات وأشياء أخرى كثيرة.</li><li>أو اقرأ كتاب <em><a rel="external nofollow" href="http://www.amazon.com/Test-Driven-JavaScript-Development-Developers-Library/dp/0321683919/ref=sr_1_1?ie=UTF8&amp;qid=1366506174&amp;sr=8-1&amp;keywords=test+driven+javascript+development">Test-Driven JavaScript Development</a></em> لمؤلّفه Christian Johansen، صاحب مكتبة Sinon. هذا الكتاب مرجع ثمينٌ وضخم في موضوع اختبارات JavaScript</li></ul><p> </p><p>ترجمة -وبتصرّف- للمقال  <a rel="external nofollow" href="http://alistapart.com/article/writing-testable-javascript">Writing Testable JavaScript</a>  لصاحبته Rebecca Murphey</p>
]]></description><guid isPermaLink="false">18</guid><pubDate>Tue, 03 Mar 2015 19:09:19 +0000</pubDate></item><item><title>&#x62A;&#x635;&#x645;&#x64A;&#x645; &#x627;&#x644;&#x646;&#x651;&#x635;&#x648;&#x635; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x64A;&#x651;&#x629;: &#x62A;&#x646;&#x638;&#x64A;&#x645; JavaScript</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D9%86%D9%91%D8%B5%D9%88%D8%B5-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%91%D8%A9-%D8%AA%D9%86%D8%B8%D9%8A%D9%85-javascript-r14/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_03/js_480x300.jpg.d7a0dc5cbcd3b774877dc873cc06c907.jpg" /></p>
<p>التّصميم الجيّد للمُنتجات يعني الاعتناء بالنواحي المهمّة للمنتج وإيلاءها اهتمامًا أكبر لتكونَ النتيجة واجهة استخدام جميلة ومُفيدة ومفهومة، لكن إياك أن تظنّ أنّ التصميم يقع على عاتق المُصمّمين فقط!</p><p>التصميم مطلوب في النصوص البرمجية، ليس فقط في النصوص البرمجية المكتوبة لبناء الواجهات المرئيّة للمستخدم — بل المقصود تصميم النّصوص البرمجيّة <em>ذاتها</em>.</p><p>النّصوص المُصمّمة بإتقان أسهل صيانةً وإمكانيّة تطويرها والبناء عليها أكبر، ممّا يجعل المُطوّرين أكثر كفاءة، لأنّها تسمح بتوجيه الاهتمام والجهد نحو بناء مُنتجات أفضل، والنتيجة شعورٌ عامّ بالراحة - راحة المطوّرين والمستخدمين وكلّ من يهمّه الأمر!</p><p>لتصميم النّصوص البرمجيّة نواحٍ ثلاث عامّة غير مرتبطة بلغة برمجة مُعيّنة:</p><ol><li>بنية النظام: المُخطّط العامّ لمجموعة ملفّات المشروع، والقواعد الّتي تُحدد كيف تتواصل مكوّناته المختلفة فيما بينها، سواء كانت نماذج البيانات أم واجهات العرض أم المُتحكّمات.</li><li>إمكانية الصيانة: إلى أي حدّ يمكن تحسين النصّ البرمجيّ والبناء عليه؟</li><li>إعادة الاستخدام: هل يمكن إعادة استخدام مكوّنات المشروع؟ هل يسهُل تخصيص أحد هذه المكوّنات لإعادة استخدامه؟</li></ol><p>التصميم المُتقن للنّصوص البرمجية في اللّغات المرنة مثل JavaScript يفرض على المطوّر إلزام نفسه بمجموعة من القواعد، لأنّ بيئة JavaScript المُتسامحة قد تسمح للمشروع أن يعمل وإن كانت أجزاؤه مبعثرة هنا وهناك. لذلك فإن تأسيس بنية المشروع والالتزام بها منذ البداية يضمنان انسجامه حتّى تمامه.</p><p>نمط الوحدات (module pattern) هو إحدى الطّرق المُجرّبة والّتي أثبتت فائدتها في تصميم البرمجيّات، إذ تتلاءم بنيتها القابلة للتوسيع مع ما يتطلّبه بناء مشروع برمجيّ متماسك وسهل الصّيانة. أعتمدُ هذا النّمط في بناء إضافات jQuery لأنّه يسمح بإعادة استخدام الوحدات وضبطها من خلال مجموعة من الخيارات عبر واجهة برمجيّة مُتقنة التّصميم.</p><p>سنستعرض فيما يلي كيف يُكتبُ نصّ برمجيّ موزّع في مكوّنات يمكن استخدامها في مشاريع أخرى لاحقة.</p><h2>نمط الوحدات</h2><p>تكثر أنماط التّصميم، وتكثر معها مصادر تعلّمها. كتب <a rel="external nofollow" href="https://twitter.com/addyosmani">Addy Osmani‏</a> كتابًا ممتازًا (ومجّانيًّا!) عن أنماط التّصميم في JavaScript، أنصح كلّ المطوّرين من كلّ المستويات بالاطّلاع عليه.</p><p>يٌسهّل <a rel="external nofollow" href="http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript">نمط الوحدات</a> تنظيم المشروع ويضمن بقاءه نظيفًا ومرتّبًا، والوحدة التي نقصدها ليست سوى كائن JavaScript حرفيّ تقليديّ (object literal) يتضمّن وظائف (methods) وخصائص (properties)، وهذه البنية البسيطة هي أفضل ما في نمط الوحدات لأنّها تسمح حتى لغير المتمرّسين ممّن يطّلعون على النّصّ البرمجيّ أن يقرؤوه ويفهموا بسرعة كيف يعمل.</p><p>في التّطبيقات التي تتبنّى هذا النّمط، يكون لكلّ مكوّن فيه وحدة منفصلة تتبع له؛ فمثلاً، يمكن لحقل نصّ في الواجهة المرئيّة يسمح بالإكمال التلقائيّ للكلمات أن يُبنى من وحدتين، الأولى للحقل ذاته، والأخرى لقائمة الكلمات المُقترحَة. تتواصل الوحدتان فيما بينهما دون أن يتداخل نصّاهما البرمجيّان معًا.</p><p>هذا العزل بين المكوّنات هو ما يجعلها مناسبة لإقامة بنية متماسكة للمشاريع، حيث تكون العلاقات بين أجزاء التطبيق محدّدة بدقّة؛ ويتولّى حقل النّصّ ما يرتبط به ضمن وحدته، ولا تُترك هذه الأمور مبعثرة بين الملفّات — لنحصل بالنّتيجة على نصّ برمجيّ واضح.</p><p>توفّر البنية القائمة على الوحدات فائدة أخرى، إذ تسمح طبيعتها بتسهيل صيانة المشروع، وذلك بتطوير كلّ وحدة بصورة منفصلة دون أن تتأثّر بقيّة أجزاء التّطبيق.</p><p>استخدمت نمط الوحدات لإنشاء إضافة <a rel="external nofollow" href="http://jpanelmenu.com">jPanelMenu‏</a>، وهي إضافة لـjQuery تسمح بإنشاء قائمة للموقع خارج الشاشة (off-canvas menu). سأستخدم هذه الإضافة كمثال عن بناء وحدة وفق هذا النمط.</p><h2>بناء الوحدة</h2><p>بدايةً سأفرض ثلاث وظائف وخاصّة واحدة تُستخدم جميعها للتفاعل مع القائمة.</p><pre class="javascript ipsCode prettyprint">var jpm = {
    animated: true,
    openMenu: function( ) {
        …
        this.setMenuStyle( );
    },
    closeMenu: function( ) {
        …
        this.setMenuStyle( );
    },
    setMenuStyle: function( ) { … }
};</pre><p>الفكرة هنا هي تجزئة النصّ إلى أصغر أجزاء مُفيدة ويمكن إعادة استخدامها. كان بإمكاننا كتابة وظيفة واحدة <code>toggleMenu( )‎</code> لتبديل وضع القائمة بين الظهور والخفاء، ولكن إنشاء وظيفتين منفصلتين <code>openMenu( )‎</code> و<code>closeMenu( )‎</code> يعطينا تحكّمًا أكبر ويسمح بإعادة استخدامهما ضمن الوحدة.</p><p>لاحظ أنّ استدعاء وظائف الوحدة وخواصّها من ضمن الوحدة ذاتها (مثل استدعاء <code>setMenuStyle( )‎</code>) يُسبق بالكلمة المفتاحية <code>this</code>، فهذه هي طريقة وصول الوحدات إلى أعضائها.</p><p>هذه هي البنية الأساسيّة لكلّ وحدة. يمكنك إضافة خواص ووظائف أخرى عند الحاجة إليها، ولكنّ الوحدة ستبقى بالبساطة ذاتها. بعد إقامة الأساسات السابقة، يمكن بناء طبقة فوقها لإعادة استخدام الوحدة، وذلك من خلال إتاحة ضبط خيارات الوحدة والتحكم بها.</p><h2>إضافات jQuery</h2><p>قد يكون الجانب الثالث للتصميم المُتقن هو الجانب الأهمّ: إعادة الاستخدام. هذه الفقرة يرافقها تحذير؛ فعلى الرغم من وجود طرق لكتابة مكوّنات يمكن إعادة استخدامها بـJavaScript "ساده"، إلّا أنّني أفضّل بناء الوحدة على صورة إضافة jQuery عندما تكون الأمور مُعقّدة، ولهذا أسباب عدّة.</p><p>أهمّ هذه الأسباب: بناء الوحدة بصورة إضافة jQuery يوصل للمُطوّرين رسالة ضمنيّة بأنّ وحدتنا تعتمد على وجود jQuery، فهذا يجب أن يكون واضحًا منذ البداية لمن يُريد استخدامها.</p><p>يُضاف إلى السّبب السّابق أنّ النّص البرمجيّ الّذي سنكتبه سيكون مُنسجمًا مع بقيّة أجزاء المشروع المُقامة على jQuery، وهذا جيّد لاعتبارات جماليّة أولًا، ولأنّه يسمح للمطوّرين بفهم استخدام الإضافة إلى حدٍّ ما دون كثير عناء، فهي إذًا طريقة أخرى لتحسين الواجهة البرمجيّة الّتي سيتخدمها المطوّرون.</p><p>قبل البدء ببناء إضافة jQuery، تأكّد من أنّها لا تتعارض مع مكتبات JavaScript أخرى تستخدم الرّمز <code>$</code>. لا تقلق فالأمر أبسط ممّا يبدو، كلّ ما عليك هو إحاطة نصّ الإضافة بما يلي:</p><pre class="javascript ipsCode prettyprint">(function($) {
    // نص الإضافة البرمجي هنا
})(jQuery);</pre><p>بعد ذلك سنُعدُّ الإضافة ونُلقي بالوحدة الّتي كتبناها سابقًا ضمن الإضافة. إضافة jQuery ليس إلا وظيفة مُعرِّفة على الكائن <code>$</code> (كائن jQuery).</p><pre class="javascript ipsCode prettyprint">(function($) {
    $.jPanelMenu = function( ) {
        var jpm = {
            animated: true,
            openMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            closeMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            setMenuStyle: function( ) { … }
        };
    };
})(jQuery);</pre><p>كل ما علينا لاستخدام الإضافة استدعاء الدّالة الّتي أنشأناها للتّوّ.</p><pre class="javascript ipsCode prettyprint">var jpm = $.jPanelMenu( );</pre><h2>الخيارات</h2><p>لا تكون الإضافة صالحةً لإعادة الاستخدام إن لم تُتِح تخصيصها وفق متطلّبات المشروع، فكلّ مشروع له أسلوبه الخاصّ وبنيته الخاصّة، وإتاحة ضبط الوحدة بالخيارات يسمح للإضافة بالتكيّف مع حاجات المشاريع المختلفة.</p><p>تزويد الوحدة بقيم مبدئية للخيارات أمرٌ مفضَّل. أسهل طريقة لفعل ذلك استخدام وظيفة jQuery ‏<code>‎$.extend()‎</code> الّتي تستقبل على الأقل مُعاملين اثنين (arguments).</p><p>اجعل المُعامل الأول لهذه الوظيفة كائنًا يوفّر كل الخيارات المتاحة وقيهما المبدئيّة، واجعل المعامل الثاني الخيارات الّتي يُقدّمها المُطور الّذي يستخدم الإضافة. ستقوم الوظيفة بدمج الكائنين مع إحلال الخيارات الّتي قدّمها المّطوّر مكان مقابلاتها المبدئيّة.</p><pre class="javascript ipsCode prettyprint">(function($) {
    $.jPanelMenu = function(options) {
        var jpm = {
            options: $.extend({
                'animated': true,
                'duration': 500,
                'direction': 'left'
            }, options),
            openMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            closeMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            setMenuStyle: function( ) { … }
        };
    };
})(jQuery);</pre><p>إضافةً إلى توفير القيم المبدئيّة، تشرح الخيارات نفسها بنفسها، أي يستطيع من يقرأ النّصّ البرمجيّ رؤية كلّ الخيارات المُتاحة مباشرةً.</p><p>أتِح أكبر عددٍ ممكن من الخيارات، فهذا قد يكون مُفيدًا في المستقبل، والمرونة لن تضرّ!</p><h2>الواجهة البرمجيّة</h2><p>الخيارات الّتي تتيحها الإضافة وسيلة رائعة لتخصيص عملها، وأمّا الواجهة البرمجيّة، فهي تتيح توسيع وظيفة الإضافة بكشف محتوى الإضافة من خصائص ووظائف ليستطيع المشروع الاستفادة منها.</p><p>مع أنّ إتاحة أكبر ما يمكن من الوحدة عبر الواجهة البرمجيّة أمرٌ حسن، إلا أنّه ليس على من يستخدمها من الخارج الوصول إلى كلّ المكوّنات الدّاخليّة. أتِح في الواجهة البرمجيّة العناصر الّتي ستُستخدم فقط.</p><p>في مثالنا، يجب على الإضافة أن تُتيح الوصول إلى وظائف فتح القائمة وإغلاقها فقط، أمّا الوظيفة الداخليّة <code>setMenuStyle( )‎</code> فيجب أن تُستدعى عندما تُفتح القائمة أو تغلق، ولكن ليس على الأجزاء الخارجيّة من المشروع أن تصل إليها.</p><p>لكشف الواجهة البرمجيّة، أعِد كائنًا يحوي الوظائف والخصائص المرغوب كشفها في نهاية نصّ الإضافة، بإمكانك أيضًا ربط الكائنات المُعادة مع تلك المُحتواة ضمن الوحدة؛ وفي هذا التنظيم يكمن جمال نمط الوحدات.</p><pre class="javascript ipsCode prettyprint">(function($) {
    $.jPanelMenu = function(options) {
        var jpm = {
            options: $.extend({
                'animated': true,
                'duration': 500,
                'direction': 'left'
            }, options),
            openMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            closeMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            setMenuStyle: function( ) { … }
        };

        return {
            open: jpm.openMenu,
            close: jpm.closeMenu,
            someComplexMethod: function( ) { … }
        };
    };
})(jQuery);</pre><p>ستكون خصائص الواجهة ووظائفها متاحةً عبر هذا الكائن الّذي أُعيد بعد تهيئة الإضافة.</p><pre class="javascript ipsCode prettyprint">var jpm = $.jPanelMenu({
    duration: 1000,
    …
});
jpm.open( );</pre><h2>"صقل" واجهة المُطوّرين</h2><p>باتّباع الخطوط العامّة البسيطة والقليل من المفاهيم، أنشأنا لأنفسنا إضافة صالحةً لإعادة الاستخدام والتّوسعة، وهذا سيُسهّل عملنا كثيرًا، وككلّ ما نُنجزه تبقى التّجربة العامل الحاسم قبل اعتماد هذا النّمط على مستوى فريقك، وبما يُناسب سياق عملك.</p><p>كلّ ما وجدت نفسي أكتب شيئًا يمكن إعادة استخدامه لاحقًا، بادرتُ لفصله في إضافة jQuery مبنيّة كوحدة. أفضل ما في هذا الأسلوب أنّه يجبرك على استخدام النّصّ الّذي تكتبه وتجربته، وعندما تستخدم شيئًا وأنت تُنشئه، يكون تحديد مواضع القوّة ومواضع الضّعف أسرع، الأمر الّذي يسمح لك بتغيير خطّة العمل باكرًا.</p><p>هذه العمليّة تُعطي في النّهاية نصًّا برمجيًّا مُجرّبًا وجاهزًا لإتاحته كمشروع مفتوح المصدر يستقبل المساهمات، وقد قمت بالفعل بنشر إضافاتي (الّتي أعتبرها شبه ممتازة) على <a rel="external nofollow" href="https://github.com/acolangelo">GitHub‏</a>.</p><p>وحتّى إن لم ترغب بنشر ما تكتبه للعموم، فإنّ تصميم النّصّ البرمجيّ أمر شديد الأهمّيّة، وستشكر نفسك بسببه في المستقبل!</p><p> </p><p>ترجمة -وبتصرّف- للمقال <a rel="external nofollow" href="http://alistapart.com/article/the-design-of-code-organizing-javascript">The Design of Code: Organizing JavaScript</a> لصاحبه Anthony Colangelo</p><p> </p>
]]></description><guid isPermaLink="false">14</guid><pubDate>Tue, 03 Mar 2015 18:44:40 +0000</pubDate></item><item><title>JavaScript &#x62A;&#x633;&#x62A;&#x637;&#x64A;&#x639; &#x623;&#x646; &#x62A;&#x64F;&#x646;&#x638;&#x651;&#x641; &#x623;&#x637;&#x628;&#x627;&#x642;&#x643; &#x623;&#x64A;&#x636;&#x627;</title><link>https://academy.hsoub.com/programming/javascript/javascript-%D8%AA%D8%B3%D8%AA%D8%B7%D9%8A%D8%B9-%D8%A3%D9%86-%D8%AA%D9%8F%D9%86%D8%B8%D9%91%D9%81-%D8%A3%D8%B7%D8%A8%D8%A7%D9%82%D9%83-%D8%A3%D9%8A%D8%B6%D8%A7-r13/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_03/javascript-all-the-things_480x300.png.c63b994f52035d5d6901d502c255cd2f.png" /></p>

<p>كما هو عليه الحال كل بضع عقود، تطفو إلى السطح لغة برمجة ما ويعدنا المتعصبون لها بأنها ستفعل لنا كل شيء، بدءًا من تطبيقات الحاسوب مرورًا بالهواتف الذكية وليس انتهاءً بالتعامل مع الجمادات من حولنا بطرق رائعة <a rel="external nofollow" href="https://www.youtube.com/watch?v=7b_epE3XG34">كالتحكم بطائرة بلا طيّار باستخدام قبضة Xbox 360</a>! لم يكن هذا الحماس يومًا أشدّ منه مع JavaScript، والأمر يعود لعدّة أسباب:</p><ul><li>كونها تعمل في المتصفح جعلها <strong>عابرة للمنصات</strong>، فكل حاسوب وكلّ هاتف ذكي (أو حتى متوسّط الذكاء!) اليوم يأتي مزوّدًا بمتصفّح قادر على تشغيل JavaScript،</li><li>وبما أنّها لغة الويب الوحيدة التي يمكن استعمالها لبرمجة المواقع من جهة المتصفّح، فلك أن تتخيّل <strong>عدد مطوّري الويب الذي يتقنونها</strong> حول العالم!</li><li>كذلك كون JavaScript بطبيعتها لغة <strong>فائقة المرونة</strong> لدرجة أن كل شيء فيها هو في الحقيقة كائن <code>Object</code> حتى الدّوال (functions)! ولا يوجد شيء اسمه أصناف (classes) بالمعنى التّقليديّ، وإنما توجد وراثة أنموذجية (Prototypal inheritance) فكل كائن يستطيع أن يرث أي كائن آخر، ولا أنواع محدّدة للكائنات، فما تفرضه في البداية كسلسلة نصيّة يمكنك أن تغيّره فيما بعد ليصبح رقمًا، وبإمكانك توسعة الأنماط البدئية. هذه المرونة التي يألفها من يبتدئ البرمجة بـJavaScript تجعله يُصاب بصدمة عندما ينتقل إلى لغة أخرى تفرض عليه قيودًا في التصريح عن الأنواع ووراثة الأصناف...</li><li>الأمر الثالث الذي يجعل JavaScript متفوّقة هو التحسّن الممتاز في أدائها الذي لا يبدو أنه سيتوقّف عند حدّ ما قريبًا، منذ بضع سنوات عندما ظهر Google Chrome مع محرّك JavaScript الجديد V8 والذي اعتمد على <a rel="external nofollow" href="https://en.wikipedia.org/wiki/Just-in-time_compilation">JIT compilation</a> بدأت ثورة في عالم التطوير للويب جعلت JavaScript موضع اهتمام وأخذ المطوّرون ينظرون في إمكانيّة استعمالها في تطوير "تطبيقات ويب" بدل "مواقع ويب"، ثم توسّع الأمر مع ظهور <a rel="external nofollow" href="http://nodejs.org">Node.js</a> التي قامت على محرّك V8 ذاته لتصبح JavaScript مواطنًا من الدّرجة الأولى على الخواديم مثلها مثل Ruby on Rails وPHP. الأمور ليست ورديّة تمامًا لكنك تستطيع استيعاب سرعة التطوّر الذي تشهده JavaScript وخاصّة أنّه أصبح لدينا أنظمة تشغيل ليست سوى متصفّح ويب في حقيقتها (Chrome OS وFirefox OS). بإمكانك استضافة تطبيقات Node.js مجّانًا على منصّة <a rel="external nofollow" href="https://www.heroku.com">Heroku</a> أو <a rel="external nofollow" href="https://openshift.redhat.com/">OpenShift</a> من RedHat مثلها مثل تطبيقات Java وPython وRuby.</li></ul><p>باختصار، تحوّلت JavaScript إلى لغة عامّة الأغراض (general-purpose) بعد أن كانت تستخدم بشكل بسيط لإضفاء القليل من التأثيرات السخيفة (Blink! Blink!) على صفحات الويب.</p><p>الآن أريد أن أوضّح شيئًا، في الحقيقة أنا لست مُبرمجًا مُختصًّا، وJavaScript هي اللغة الوحيدة التي أزعم أنّني متوسّط إلى خبير بها، ومنذ عام أو أكثر لم أكتب تقريبًا أي شيء بلغة أخرى (بالطّبع <a rel="external nofollow" href="http://coffeescript.org/">CoffeeScript</a> لا تُعتبر لغة مستقلّة، هي فقط لغة تُحوّل إلى JavaScript ومهمّتها تبسيط الكتابة)، مع أنّني بدأت تعلّم البرمجة مع PHP، إلا أنّني كرهت كل إشارات الدولار تلك (<code>$variable</code>) وعدم انسجام الواجهات البرمجيّة فيها. لا شيء يمنعك من استخدام PHP، وفي الحقيقة إطار العمل <a rel="external nofollow" href="http://laravel.com/">Laravel</a> ممتاز ومنسّق بشكل جيّد، لكنّ ما يعيبها هو أنها تحاول أن تفعل كلّ شيء من الوصول لنظام الملفّات إلى دوال للتعامل مع مُعاملات طلبات HTTP إلخ... وهذا بالضّبط ما تحاول بيئات البرمجة الجديدة أن تتجنّبه، ففي Node.js، وعلى الرّغم من أنّه باستطاعتك أن تصل إلى نظام الملفّات وأن تُنشئ خادمًا يستمع إلى الطلبات على أحد المنافذ؛ إلّا أنّ كلّ شيء مُنظّم في وحدات (modules) مستقلّة وعليك أن تُصرح علانيًّة برغبتك باستعمال وحدة نظام الملفّات مثلاً، وكذلك الأمر بالنسبة للوحدات التي يكتبها مبرمجون آخرون. نظام الوحدات هذا والتصريح عنها ضمن ملفّ وعدم تلويث نطاق الأسماء العامّ (Global scope) هي بعضٌ من الأشياء التي نفّذها مُطوّرو Node.js على وجه صحيح، وأزعم أنه واحد من الأشياء التي جعلت JavaScript تُؤخذ على محمل الجدّ. هناك الكثير من المحاولات لتقليد هذا النظام بعد أن أثبت تفوّقه، انظر مثلاً إلى <a rel="external nofollow" href="http://www.webtuts.me/php-composer/">Composer</a> بالنسبة لـPHP، و<a rel="external nofollow" href="http://pip-installer.org/">Pip</a> مع <a rel="external nofollow" href="https://pypi.python.org/pypi/virtualenv">virtualenv</a> في Python؛ لكنّ محاولة إدخال هذه الأنظمة على لغات ناضجة لا تبدو موفّقة كثيرًا، وأما في لغة Go فتعتبر <a rel="external nofollow" href="http://golang.org/pkg/">الحُزم</a> شيئًا من أساس اللغة. أيًّا يكن، لقد وصلنا إلى مرحلة يمكن بها إنجاز أيّة تطبيق بأيّة لغة، ويبقى الفارق هو التنظيم والسرعة والأمان وأنماط التّصميم المُتّبعة، وأهمّ من ذلك كلّه المجتمع الّذي يوفّر الدّعم والمساعدة للمبتدئين (في النّقطة الأخيرة لا شكّ أن JavaScript متفوّقة على كلّ اللّغات).</p><p>لكن دعونا لا نُهين قدرتنا العقلية ونتجاهل وجود لغات برمجة أخرى فقط لأنّنا ألِفنا لغة برمجة واحدة، مهما كانت محبوبة! هناك أشياء في JavaScript لا يمكن التّغاضي عنها ولا يُمكن في أحسن الأحوال أن نعتبرها مزايا:</p><ul><li>فهي أوّلاً <strong>بطيئة</strong> رغم تحسّن أدائها بأضعاف ما كانت عليه منذ سنوات، وما تزال أبطأ بكثير من لغات أخرى. هناك من يجادل (وأنا أؤيّد هذا الرأي) أن السّرعة ليست كلّ شيء، فيكفي لتطبيقات الويب أن تكون سريعة بما يكفي، وليس عليها أن تكون خارقة السرعة، الفارق بين كتابة تطبيق بسيط يؤدي مهمّة محدّدة بـJavaScript وتوزيعه ليعمل على كلّ منصّات الهواتف الذكية أمر يستحق التضحية بالقليل (والقليل فقط، أي إلى حدّ معقول) من السّرعة في مقابل كتابة تطبيق منفصل بـJava (لن تتخيّل عدد السّطور المُرعب الذي تحتاجه!) وآخر بـObjective C (أو Swift) وآخر بلغة ما لـWindows Phone (إن كان هناك من يُطوّر لهذا النظام! ونعم أنا جاهل به لدرجة أنّني لا أعرف شيئًا عن اللّغة التي تُستخدم لتطوير تطبيقاته!). لكن بعد تجاوز هذا الحد المعقول من التضحية، يجدر بك أن تُعيد النظر في صلاحية هذه اللّغة إذا ما أردت تطبيقًا ينفّذ مهمّة تتطلّب سرعة فائقة، دعك من أنّ هناك تطبيقات تحتاج إلى التعامل مع النظام بطريقة لا توفّرها بيئة تطبيقات الويب على هذه الأجهزة.</li><li>وثانيًا JavaScript هي <strong>عالم من الفوضى</strong> إن تغاضينا عن التنظيم الممتاز في Node.js ونظرنا إلى بيئة المتصفّحات... كم مرّة عانى مطوّرو الويب من عدم التوافق... المتصفّح الفلاني يوفّر الميزة الفلانية... رائع! هذا بالضبط ما أحتاجه! لكن للأسف المتصفح الآخر لا يوفّرها، وستحتاج إلى مكتبة بديلة (<a rel="external nofollow" href="https://en.wikipedia.org/wiki/Polyfill">polyfill</a>) لسدّ هذا الفراغ، حسنًا سأضيف هذا الـpolyfill وسيمكنني التطوير لكل المتصفّحات... نعم، باستثناء أنّ هذا الـpolyfill يسدّ الفراغ بنسخة قديمة من معيار هذه الميزة التي تحتاجها - فكما تعرف أعضاء منظّمة <a rel="external nofollow" href="http://www.w3.org/">W3C</a> لا يتوقّفون عن تغيير الواجهات البرمجيّة للأشياء التجريبية في المتصفّحات... ألم نُحذّرك من استخدام هذه الميزة غير المُستقرّة؟ كان يجدر بك أن تبحث عن حلّ بديل!... وهذا هو بالضّبط السّبب الذي يجعلني أكره التطوير للواجهات (front-end development) ولهذا قرّرت الاعتزال في عالم Node.js والتطوير للنهاية الخلفيّة (backend)! لا شيء من أحلامك الورديّة يتحقّق بسهولة في عالم المتصفّحات! أعرف أن الأمور في تحسّن دائم، وهناك الكثير من الأشياء الرائعة القادمة... مثل <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache"><code>applicationCache</code></a> و<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API"><code>indexedDb</code></a> و<a rel="external nofollow" href="http://www.html5rocks.com/en/tutorials/es7/observe/"><code>Object.observe</code></a> و<a rel="external nofollow" href="http://toddmotto.com/web-components-concepts-shadow-dom-imports-templates-custom-elements/">Web Components وHTML Imports</a>... لكنّ المشكلة أنها جميعها ليست مستقرّة أو غير مُتبنّاة في كلّ المتصفّحات بعد؛ ويبدو أن هذه الفوضى لن تنتهي يومًا، ولا حلّ لها سوى المزيد من فوضى المكتبات البديلة، هل قلت يومًا إنّ الويب هو مستقبل التطوير الموحّد لكلّ المنصّات؟ لقد كنت ساذجًا!</li><li>هناك الكثير من عيوب التصميم في JavaScript، بعضها يعود لكونها لغة صُمّمت لإنجاز مهام بسيطة وعلى عجَلَ (في الحقيقة <a rel="external nofollow" href="https://twitter.com/BrendanEich">Brendan Eich</a> صمّمها خلال 10 أيام لمتصفّح Netscape)، فمثلاً لا يُمكنك إنشاء خيوط (<a rel="external nofollow" href="https://en.wikipedia.org/wiki/Thread_%28computing%29">threads</a>) لأنّها تعمل ضمن خيط واحد (single-threaded)، هناك الكثير من الحلول الالتفافيّة (workarounds) في Node.js والمتصفّحات تعدنا بحل محدود الفعاليّة (<a rel="external nofollow" href="https://developer.mozilla.org/en/docs/Web/Guide/Performance/Using_web_workers">Web Workers</a>) لكنّ إيّاك أن تُخبر مُبرمج Java بأنّه لا يُمكنك إنشاء threads في JavaScript ثمّ تدعي أنّها لغة قويّة! أيضًا لا تستغرب إن قضيت ساعات تشرح لمطوّري اللّغات الأخرى عن حلقة الأحداث (<a rel="external nofollow" href="https://vimeo.com/96425312">event loop</a>) وكيف تعمل ولماذا عليك تمرير استدعاءات راجعة (callbacks) عندما تُنفّذ طلبات <code>XMLHttpRequest</code> وما هو جحيم الاستدعاءات (<a rel="external nofollow" href="http://callbackhell.com/">callback hell</a>) ولماذا ظهرت بدائل عنها مثل الوعود (<code>Promise</code>) التي تحوّل جحيم الاستدعاءات إلى جحيم <code>then</code>!</li></ul><pre class="javascript ipsCode prettyprint">asynctask1(function(err1, data1) {
  if (err1) {
    throw err1;
    return;
  }
  asynctask2(data1, function(err2, data2) {
    if (err2) {
      throw err2;
      return;
    }
    asynctask3(data2, function(err3, data3) {
      // ... WELCOME TO JAVASCRIPT!
    })
  })
});</pre><ul><li>أخيرًا أرجوك لا تنسى بديهيّة أن JavaScript بحدّ ذاتها لغة تُفسّر بمحرّك مكتوب بـC++ أو لغة أخرى أعرق وأقوى أداءً، النّواة Linux مكتوبة بخليط من C وC++ وبرامج تشغيل الأجهزة (drivers) غالبًا تُكتب بـ<a rel="external nofollow" href="https://en.wikipedia.org/wiki/Assembly_language">Assembly</a>. نعم، صدّقني JavaScript ليست اللّغة الوحيدة ضمن المجموعة الشّمسيّة!</li></ul><p>ضحكت كثيرًا عندما شاهدت هذه الصورة منذ بضعة أسابيع، التي تُعبّر بالضّبط عن موضوع هذه التدوينة:</p><p style="text-align:center;"><a class="ipsAttachLink ipsAttachLink_image" rel="external nofollow" href="https://academy.hsoub.com/uploads/monthly_2015_02/javascript-all-the-things.jpg.be57b38809d8632c5d06605100d47e1b.jpg"><img class="ipsImage ipsImage_thumbnailed" data-fileid="5" alt="javascript-all-the-things.thumb.jpg.711b" src="https://academy.hsoub.com/uploads/monthly_2015_02/javascript-all-the-things.thumb.jpg.711bf6337daf5dfa7abbf17dff79421f.jpg"></a></p><p>تسخر هذه الصّورة بشدّة من تعصّب بعض مبرمجي JavaScript الذي يدعوهم إلى الظنّ بأنّ على كل تطبيق جديد في الكرة الأرضية أن يستخدم JavaScript من اليوم فصاعدًا، وأنّ لغات أخرى ستصبح طيّ النسيان ولا يستخدمها إلّا المبرمجون القدامى الذين عفى عليهم الدهر؛ الأمر ليس مقتصرًا على متعصّبي JavaScript وحدهم، فلكلّ لغة برمجة أنصارها ومتعصّبوها، لكن JavaScript بالذّات هي أكثر اللغات التي تترافق بهذه الظاهرة، للأسباب التي ذكرتها سابقًا.</p><h2>ما خُلاصة هذا الحديث؟</h2><p>ما أريد قوله من هذه التدوينة السّريعة هو أن أنصح المتعصّبين للغة برمجية أيًّا كانت أن يتوقّفوا عن إهانة قدراتهم العقليّة على التّعلّم وتقبّل الكتابة بلغة أخرى يرون أنّها للفاشلين فقط أو للقادمين من العصر الحجري... لم أتعلّم هذا إلا بالطّريقة الصّعبة، وأعتقد أنّ السّبب الّذي جعلني أتقبّل هذه الحقيقة هو كوني غير مختصّ، تعلّمي للبرمجة غير مرهون بعملٍ أو بربح مادّيٍّ، أنا فقط أُبرمج على سبيل التّسلية، وكلّ مشاريعي التي كتبتها (<a rel="external nofollow" href="https://github.com/forabi/forabi.github.io">هذه المدوّنة</a> بنيتها من الصّفر، وتطبيق <a rel="external nofollow" href="https://github.com/forabi/aQuran">aQuran</a>، و<a rel="external nofollow" href="https://github.com/forabi/refeed">تطبيق جديد أكتبه لتوليد خلاصات RSS</a>...) كلّها كانت مجرّد تجربة ومحاولة لاستكشاف أنماط التصميم (design patterns) ومفاهيم برمجيّة أخرى. نعم تعلّمت الكثير عن البرمجة عمومًا من خلال JavaScript، لكنّها لن تكون اللّغة الوحيدة التي أكتب بها لبقيّة حياتي بالطّبع! يبدو أن هدفي التالي سيكون لغة <a rel="external nofollow" href="https://en.wikipedia.org/wiki/Go_%28language%29">Go</a> حديثة العهد. البرمجة أوسع من صياغة اللّغة (syntax) لذا فلا يعتبر انتقالي لتعلّم لغة أخرى خسارة، والكثير من المفاهيم البرمجية <a rel="external nofollow" href="http://www.rwaq.org/courses/test-driven-development">كالبرمجة المُقادة بالاختبارات</a> (test-driven development) والتّعامل مع الاستثناءات (exception handling) ومكوّنات اللغة كالأصناف (classes) والواجهات (interfaces) والدّوالّ (functions) هي أشياء توجد بعضها أو كلّها في كلّ اللّغات.</p>
]]></description><guid isPermaLink="false">13</guid><pubDate>Sun, 10 Aug 2014 19:28:00 +0000</pubDate></item><item><title>&#x645;&#x627; &#x627;&#x644;&#x62C;&#x62F;&#x64A;&#x62F; &#x641;&#x64A; &#x627;&#x644;&#x625;&#x635;&#x62F;&#x627;&#x631; &#x627;&#x644;&#x642;&#x627;&#x62F;&#x645; &#x645;&#x646; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; (ECMAScript 6) - &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x623;&#x648;&#x644;</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D8%A7-%D8%A7%D9%84%D8%AC%D8%AF%D9%8A%D8%AF-%D9%81%D9%8A-%D8%A7%D9%84%D8%A5%D8%B5%D8%AF%D8%A7%D8%B1-%D8%A7%D9%84%D9%82%D8%A7%D8%AF%D9%85-%D9%85%D9%86-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-ecmascript-6-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r12/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_02/es6.jpg.3601719c3d91cc54d52cfc613db1e9a7.jpg" /></p>

<p><strong>Harmony</strong> هو الاسم الرمزي لـ  <strong>ECMAScript 6</strong> وهي اللغة القياسية التي تقوم عليها <strong>JavaScript</strong>، والإصدار الجديد يأتي بميزات جديدة تتناول العديد من جوانب اللغة بما فيها الصياغة (syntax) وأسلوب البناء وأنواع جديدة من المكونات المدمجة في اللغة. في هذا المقال نتعرف على بعض من المميزات التي ستجعل كتابة شيفرة <strong>جافاسكربت</strong> أكثر اختصاراً وفعالية.</p><p style="text-align:center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_02/ecmascript6-javascript.png.1c401ccee42d1f12adcabafe9c771bd5.png" rel="external nofollow"><img class="ipsImage ipsImage_thumbnailed" src="https://academy.hsoub.com/uploads/monthly_2015_02/ecmascript6-javascript.thumb.png.2af88c25b4563c6a46720738eae1247a.png" data-fileid="8" alt="ecmascript6-javascript.thumb.png.2af88c2"></a></p><h2>متغيرات نطاقها القطعة البرمجية (Block-scoped Variables)</h2><p>في الإصدار الحالي من JavaScript، تُعامل كل المتغيرات المفروضة ضمن دالة (<code>function</code>) على أنها تابعة لهذه الدالة (Function-scoped) أي يمكن الوصول إليها من أي موقع ضمن هذه الدالة، حتى وإن كانت هذه المتغيرات قد فُرضِت ضمن قطعة برمجية فرعية ضمن هذه الدالة (كحلقة <code>for</code> أو جملة شرطية <code>if</code>)، وهذا يخالف ما تتبناه بعض من أشهر لغات البرمجة، وقد يسبب بعض الارتباك لمن لم يعتد عليه.<br>لنوضح أكثر في هذا المثال:</p><pre class="javascript ipsCode prettyprint">var numbers = [1, 2, 3];
var doubles = [];

for (var i = 0; i &lt; numbers.length; i++) {
   var num = numbers[i];
   doubles[i] = function() {
     console.log(num * 2);
   }
}

for (var j = 0; j &lt; doubles.length; j++) {
  doubles[j]();
}</pre><p>عند تنفيذ هذا المثال، سنحصل على الرقم <code>6</code> ثلاث مرات، وهو أمر غير متوقع ما لم نكن على معرفة بطبيعة مجالات JavaScript، ولو طبق ما يشبه هذا المثال في لغة أخرى، لحصلنا على النتيجة <code>2</code> ثم <code>4</code> ثم <code>6</code>، وهو ما يبدو النتيجة المنطقية لشيفرة كهذه.<br>ما الذي يحدث هنا؟ يتوقع المبرمج أن المتغير <code>num</code> محصور ضمن حلقة <code>for</code> وعليه فإن الدالة التي ندخلها في المصفوفة <code>doubles</code> ستعطي عند استدعائها القيمة التي ورثتها عن مجال حلقة <code>for</code> إلا أن الحقيقة هي أن المتغير <code>num</code> يتبع للمجال العام، لأن حلقة <code>for</code> لا تُنشئ مجالًا فرعيًّا وعليه فإن القيمة العامة <code>num</code> تتغير ضمن حلقة <code>for</code> من <code>2</code> إلى <code>4</code> إلى <code>6</code> وعند استدعاء أي دالة ضمن المصفوفة <code>doubles</code> فإنها ستعيد إلينا القيمة العامة <code>num</code>، وبما أن الاستدعاء يحدث بعد إسناد آخر قيمة للمتغير <code>num</code>، فإن قيمته في أي لحظة بعد انتهاء الحلقة الأولى ستكون آخر قيمة أسندت إليه ضمن هذه الحلقة، وهي القيمة <code>6</code>.</p><p>يعطينا الإصدار القادم طريقة لحل هذا الارتباك باستخدام الكلمة المفتاحية <code>let</code> بدلاً عن <code>var</code>، وهي تقوم بخلق مجال ضمن القطعة البرمجية التي تُستخدم فيها، بمعنى آخر: ستكون <code>let</code> هي بديلنا عن <code>var</code> من الآن فصاعدًا، لأنها ببساطة تعطينا النتائج البديهية التي نتوقعها. لنُعِد كتابة المثال السابق باستبدال <code>var num</code> بـ<code>let num</code>:</p><pre class="javascript ipsCode prettyprint">var numbers = [1, 2, 3];
var doubles = [];

for (var i = 0; i &lt; numbers.length; i++) {
   let num = numbers[i];
   doubles[i] = function() {
     console.log(num * 2);
   }
}

for (var j = 0; j &lt; doubles.length; j++) {
  doubles[j]();
}</pre><p>عند تطبيق هذا المثال (يمكنك تطبيقه في Firefox وChrome لأن كلا المتصفحين شرعا في دعم <code>let</code>) سنحصل على النتيجة البديهية <code>2</code> ثم <code>4</code> ثم <code>6</code>. بالطبع بإمكاننا تحسين الشيفرة باعتماد <code>let</code> عند التصريح عن كل المتغيرات السابقة، وهو الأمر الذي يجب أن تعتاد فعله من اليوم!</p><h2> </h2><h2>شيفرة أقصر وأسهل للقراءة</h2><p>لعل أكثر ما أُحبّه في JavaScript مرونتها الفائقة، وبالذات القدرة على إمرار دوال مجهولة (Anonymous Functions) لدوال أخرى، الأمر الذي يسمح لنا بكتابة شيفرة ما كان من الممكن كتابتها بلغات أخرى إلا بضعفي عدد الأسطر وربما أكثر. لاحظ هذا المثال:</p><pre class="javascript ipsCode prettyprint">var people = ['Ahmed', 'Samer', 'Khaled'];
var greetings = people.map(function(person) { return 'Hello ' + person + '!'; });

console.log(greetings); // ['Hello Ahmed!', 'Hello Samer!', 'Hello Khaled!'];</pre><p>لو أردنا تنفيذ هذه المهمة في لغة أخرى، فلربما احتجنا إلى حلقة <code>for</code> لنمرّ من خلالها على كل عنصر ضمن المصفوفة ثم إدخال العبارات الجديدة ضمن مصفوفة أخرى، وهذا يعني أن مهمة يمكن كتابتها بسطرين في JavaScript قد تتطلب 5 سطور في لغة أخرى. لو لم تمتلك JavaScript القدرة على إمرار الدالة المجهولة <code>function(person) {...}</code> أعلاه، لفقدت جزءًا كبيرة من مرونتها.</p><p>لكن الإصدار القادم من JavaScript تذهب أبعد من ذلك، وتختصر علينا كتابة الكثير من النص البرمجي. لُنعد كتابة المثال السابق:</p><pre class="javascript ipsCode prettyprint">let people = ['Ahmed', 'Samer', 'Khaled'];
let greetings = people.map(person =&gt; 'Hello ' + person + '!');

console.log(greetings); // ['Hello Ahmed!', 'Hello Samer!', 'Hello Khaled!'];</pre><p>في هذا المثال استخدمنا ما اصطلح على تسميته <strong>دوال الأسهم (Arrow Functions)</strong>، وهي طريقة أكثر اختصارًا لكتابة الدوال المجهولة، لن تحتاج لكتابة <code>return</code>، فهي ستضاف تلقائيًا عند التنفيذ. من الآن فصاعداً اعتمد دوال الأسهم عندما تريد تنفيذ دالة مجهولة بسيطة بسطر واحد.</p><p>بمناسبة الحديث عن الشيفرة المختصرة... ما رأيكم لو جعلنا الشيفرة أعلاه <em>أكثر اختصارًا</em>؟!</p><pre class="javascript ipsCode prettyprint">let people = ['Ahmed', 'Samer', 'Khaled'];
let greetings = ['Hello ' + person + '!' for (person of people)];

console.log(greetings); // ['Hello Ahmed!', 'Hello Samer!', 'Hello Khaled!'];</pre><p>قد تبدو الصياغة غريبة بعض الشيء، لكنها تتيح لنا فهم النص بسهولة أكبر، وتغنينا عن الحاجة لدالة مجهولة (الأمر الذي قد يؤثر على الأداء، وإن كان بأجزاء من الثواني). الصياغة التي استخدمناها أعلاه تُسمى <strong>Array Comprehensions</strong>، وإن كنت قادرًا على ترجمتها إلى العربية بطريقة واضحة، فلا تبخل بها علينا!</p><p>لكن... ألا ترون أنه يمكن تحسين هذه الشيفرة قليلاً؟<code class="lang-javascript"> </code></p><pre class="javascript ipsCode prettyprint">let people = ['Ahmed', 'Samer', 'Khaled'];
let greetings = [`Hello ${ person }!` for (person of people)];

console.log(greetings); // ['Hello Ahmed!', 'Hello Samer!', 'Hello Khaled!'];
</pre><p>هنا استبدلنا إشارات الاقتباس (<code>'</code> أو <code>"</code>) بالإشارة ` الأمر الذي أتاح لنا إحاطة المتغير <code>person</code> بقوسين معكوفين مسبوقين بإشارة <code>$</code>، وهذه الصياغة تدعى <strong>"السلاسل النصية المقولبة"</strong> أو Template Strings، والتي تسمح -بالإضافة إلى القولبة- بالعديد من الأشياء الرائعة، كالعبارات على عدة أسطر:</p><pre class="javascript ipsCode prettyprint">let multilineString = `I am
a multiline
string`;

console.log(multilineString);
// I am
// a multiline
// string
</pre><p><del>للأسف لن تعمل الشفرة السابقة في أي من المتصفحات الحالية، لأن السلاسل النصية المقولبة ما تزال غير معتمدة ضمن أي منها</del>. <strong>تحديث:</strong> <a rel="external nofollow" href="http://firefoxnightly.tumblr.com/post/92234218909/ecmascript-6-template-strings-are-now-supported-in">بدأ Firefox Nightly باعتمادها</a>.</p><p>من المميزات الجديدة كذلك إمكانية اختصار بناء الكائنات ذات الخصائص بالشكل التالي:</p><ul><li dir="rtl">حاليًا، نقوم بكتابة شيفرة مثل هذه:<code class="lang-javascript"> </code></li></ul><pre class="javascript ipsCode prettyprint">var createPerson = function(name, age, location) {
  return {
    name: name,
    age: age,
    location: location,
    greet: function() {
      console.log('Hello, I am ' + name + ' from ' + location + '. I am ' + age + '.');
    }
  }
};

var fawwaz = createPerson('Fawwaz', 21, 'Syria');
console.log(fawwaz.name); // 'Fawwaz'
fawwaz.greet(); // "Hello, I am Fawwaz from Syria. I am 21."
</pre><ul><li dir="rtl">في الإصدار القادم، سيكون بالإمكان كتابة الشيفرة كالتالي:</li></ul><pre class="javascript ipsCode prettyprint">let createPerson = function(name, age, location) {
  return {
    name,
    age,
    location,
    greet() {
      console.log('Hello, I am ' + name + ' from ' + location + '. I am ' + age + '.');
    }
  }
};

let fawwaz = createPerson('Fawwaz', 21, 'Syria');
console.log(fawwaz.name); // 'Fawwaz'
fawwaz.greet(); // "Hello, I am Fawwaz from Syria. I am 21."</pre><p>بما أن اسم المُعامل (parameter) يماثل اسم الخاصة (property)، فإن هذا يتم تفسيره على أن قيمة الخاصة توافق قيمة المعامل، بمعنى: <code>name: name</code>، بالإضافة إلى كتابة <code>greet() {...}</code> بدل <code>greet: function() {...}</code>.</p><p>كذلك سيكون بإمكاننا تحسين هذا النص أكثر من ذلك باستخدام <strong>الأصناف (Classes)</strong>، نعم! سيكون لدينا أصناف أخيرًا! (سنستعرضها لاحقاً)</p><h2> </h2><h2>الثوابت (Constants)</h2><p>سيداتي وسادتي... رحبوا بالثوابت... نعم إنها أخيرًا متوفرة في JavaScript، إحدى المكونات الأساسية لأي لغة برمجية التي لم تكن متوفرة في JavaScript، أصبحت الآن متوفرة. والآن نأتي للسؤال البديهي: لماذا أحتاج للثوابت؟ أليس بإمكاني التصريح عن متغير دون أن أغير قيمته بعد إعطاءه القيمة الأولية؟ نعم بالطبع بإمكانك ذلك، لكن هذا لا يعني بالضرورة أن المستخدم أو نصاً برمجيًا من طرف ثالث ليس بإمكانه تغيير قيمة هذا المتغير في سياق التنفيذ، وطالما أن المتغير "متغير" بطبيعته، فإننا دومًا بحاجة إلى شيء من أصل اللغة يحمينا من تغييره خطأ. عند التصريح عن ثابت فإننا نعطيه قيمة أولية ثم ستتولى الآلة البرمجية لـJavaScript حماية هذا الثابت من التغيير، وسُيرمى خطأ عند محاولة إسناد قيمة جديدة لهذا الثابت.</p><pre class="javascript ipsCode prettyprint">const myConstant = 'Never change this!';

myConstant = 'Trying to change your constant';
// TypeError: redeclaration of const myConstant

console.log(myConstant); // "Never change this!"</pre><h2> </h2><h2>المُعاملات الافتراضية (Default Parameters)</h2><p>غياب دعم المُعاملات الافتراضية في JavaScript واحد من أكثر الأشياء التي تزعجني، لأنها تجبرني على كتابة شيفرة مثل هذه:</p><pre class="javascript ipsCode prettyprint">function SayHello (user) {
  if (typeof user == 'undefined') {
    user = 'User';
  }

  console.log('Hello ' + user);
}

console.log(SayHello('Fawwaz')); // Hello Fawwaz!
console.log(SayHello()); // Hello User!</pre><p>لو كان عندي 3 متغيرات غير إجبارية، فهذا يعني أنني سأحتاج 3 جمل شرطية، الأمر الذي يتطلب الكثير من الكتابة المُملة. بفضل الإصدار القادم من JavaScript، سيكون بالإمكان كتابة شيفرة أبسط بكثير:</p><pre class="javascript ipsCode prettyprint">function SayHello (user='User') {
  console.log('Hello ' + user);
}

SayHello('Fawwaz'); // Hello Fawwaz!
SayHello(); // Hello User!

</pre><h2>الوعود (Promises)</h2><p>الوعود هي الحل الذي تأتينا به JavaScript لحل مشكلة هرم الموت (Pyramid of Death) الذي نواجهه عند تنفيذ مهمات غير متزامنة تعتمد إحداها على الأخرى:</p><pre class="javascript ipsCode prettyprint">function getFullPost(url, callback) {

  var getAuthor = function(post, callback) {
    $.ajax({ method: 'GET', url: '/author/' + post.author_id }, callback);
  };

  var getRelatedPosts = function(post, callback) {
    $.ajax({ method: 'GET', url: '/related/' + post.id }, callback);
  };

  $.ajax({ method: 'GET', url: url }, function(post) {
    getAuthor(post, function(res) {
      post.author = res.data.author;
      getRelatedPosts(post, function(res) {
        post.releated = res.data.releated;
        callback(post);
      });
    });
  });

}
</pre><p>هل تلاحظ أن الشيفرة تتجه نحو اليمين؟ لو أردنا تنفيذ هذه المهمات غير المتزامنة واحدة بعد الأخرى وكان عددها 10 مثلًا فستصبح الشيفرة شديدة التعقيد، كما أن هذه الطريقة ليست بديهية، ولا يمكن لك أن تفهم ماذا تفعل هذه الدالة المجهولة (المعامل الثاني في كل دالة) ما لم تألفها. ماذا لو أمكننا كتابة هذه الشيفرة بصورة أفضل؟</p><pre class="javascript ipsCode prettyprint">function getFullPost(url) {
  var post = { };
  var getPost = function(url) {
    return $http.get(url);
  };

  var getAuthor = function(post) {
    return $http.get('/author/' + post.author_id).then(function(res) {
      post.author = res.data.author;
    });
  };

  var getRelatedPosts = function(post) {
    return $http.get('/related/' + post.id).then(function(res) {
        post.related = res.data.related;
    });
  };

  return getPost().then(getAuthor).then(getRelatedPosts).catch(function(err) {
    console.log('We got an error:', err);
  });
}
</pre><p> </p><p>في الجزء القادم سنتعرّف على المكوّنات الجديدة الأكثر إثارة، كالمولّدات التي ستجعلنا نغير من طريقة تعاملنا مع البيانات اللامتزامنة كليًّا!</p>
]]></description><guid isPermaLink="false">12</guid><pubDate>Tue, 22 Jul 2014 18:50:00 +0000</pubDate></item></channel></rss>
