<?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/3/?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>&#x62A;&#x62A;&#x628;&#x639; &#x627;&#x644;&#x623;&#x62E;&#x637;&#x627;&#x621; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D8%AA%D8%A8%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2274/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_03/---.png.f8db830453526aee4b5407b15c2bc40f.png" /></p>
<p>
	لربما صادفتك بعض المشاكل عندما بنيت في <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%AC%D8%B1%D8%A8%D8%AA%D9%83-%D8%A7%EF%BB%B7%D9%88%D9%84%D9%89-%D9%85%D8%B9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2273/" rel="">مقال سابق</a> لعبة تخمين الرقم الصحيح، أو وجدت أن هذه اللعبة لا تعمل بالشكل المطلوب! لهذا سنفرد هذا المقال لمساعدتك في البحث عن المشكلات البرمجية التي قد تصادفك وإيجاد حل لها، من خلال تزويدك ببعض التلميحات والنصائح عن كيفية إيجاد وإصلاح اﻷخطاء.
</p>

<p>
	ننصحك قبل المتابعة في قراءة هذا المقال بالاطلاع على بعض المقالات السابقة مثل:
</p>

<ol>
	<li>
		أساسيات علوم الحاسوب
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/html/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-html-r1687/" rel="">أساسيات HTML</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/css/%D8%AA%D8%B9%D8%B1%D9%91%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-css-r70/" rel="">أساسيات عمل CSS</a><span style="display: none;"> </span>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1689/" rel="">أساسيات جافا سكريبت</a>
	</li>
</ol>

<h2 id="-1">
	أنواع اﻷخطاء البرمجية
</h2>

<p>
	عندما ترتكب خطأ عند كتابة الشيفرة ستواجه عمومًا نوعين من اﻷخطاء:
</p>

<ul>
	<li>
		<strong>أخطاء في الصياغة (قواعدية) syntax error</strong>: وتنتج عن الخطأ في كتابة التعليمات مما يسبب توقف عمل البرنامج تمامًا أو توقف جزء منه، وستظهر عادة بعض رسائل الخطا أيضًا. وهي عادة قابلة للإصلاح إن كنت تألف العمل على اﻷدوات المناسبة للتنقيح وتعرف ما تعنيه رسالة الخطأ.
	</li>
	<li>
		<strong>أخطاء منطقية logic errors</strong>: في هذه الحالة تكون الصياغة صحيحة، لكن الشيفرة لا تعمل كما ينبغي، أي أن البرنامج يُنفّذ بنجاح لكنه يعطي نتائج غير صحيحة. وهي أخطاء أصعب إصلاحًا لعدم توفر رسائل أخطاء توجهك إلى مصدر الخطأ.
	</li>
</ul>

<p>
	فالعملية إذًا ليست بهذه السهولة. وما ستراه عندما تتعمق في البرمجة وجود تفاصيل أخرى لأنواع اﻷخطاء، لكن التصنيف السابق هو كل ما تحتاجه في هذا المستوى المبكر من مسيرتك، وسنعمل على هذين النوعين في هذا المقال.
</p>

<h2 id="-2">
	مثال عن خطأ
</h2>

<p>
	حتى نبدأ العمل، عليك أن تعود إلى <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%AC%D8%B1%D8%A8%D8%AA%D9%83-%D8%A7%EF%BB%B7%D9%88%D9%84%D9%89-%D9%85%D8%B9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2273/" rel="">لعبة خمّن الرقم الصحيح</a>، لكن ما سنفعله أننا سنعود إلى نسخة أخرى من اللعبة ارتُكبت فيها أخطاء عمدًا. لهذا حمّل <a href="https://github.com/mdn/learning-area/blob/main/javascript/introduction-to-js-1/troubleshooting/number-game-errors.html" rel="external nofollow">نسخة منها</a>.
</p>

<ol>
	<li>
		افتح الملف ضمن المحرر النصي وضمن المتصفح.
	</li>
	<li>
		جرّب أن تلعب، وسترى أن اللعبة لا تعمل عند النقر على زر "Submit guess".
	</li>
</ol>

<p>
	<strong>ملاحظة:</strong> ربما قد حصلت بالفعل على نسخة لا تعمل عند تجريب كتابة الشيفرة بنفسك، لكننا نريد منك أن تعمل على نسختنا في هذا المقال كي تتعلم التقنيات التي نقدمها لحل المشاكل ثم يمكنك العودة بعدها لتصحيح أخطاء نسختك.
</p>

<p>
	ما سنفعله حاليًا هو الانتقال إلى "<a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B7%D9%88%D8%B1-r665/" rel="">طرفية المطوّر</a>" لنرى إن كانت تعرض أية أخطاء صياغة كي نحاول إصلاحها، وهذا ما ستتعلمه تاليًا.
</p>

<h2 id="-3">
	إصلاح أخطاء الصياغة
</h2>

<p>
	قد تكون كتبت بعض أوامر جافا سكريبت في طرفية جافا سكريبت ضمن أدوات مطوري ويب <a href="https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B7%D9%88%D9%90%D9%91%D8%B1-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%AF%D9%8A%D8%AB%D8%A9-r541/" rel="">DevTools</a>، لكن الفائدة الأكبر من كتابة الشيفرة في أدوات المطور هي رسائل أخطاء الصياغة التي تعرضها لك الطرفية عند وقوع الخطأ. لنبدأ باصطياد اﻷخطاء إذًا!
</p>

<p>
	1.انتقل إلى النافذة التي ظهرت <code>number-game-errors.html</code> ثم افتح طرفية جافا سكريبت وسترى رسالة خطأ التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="146702" href="https://academy.hsoub.com/uploads/monthly_2024_03/01_first_error.png.be5bddf3e578115419b0f5215fbe296e.png" rel=""><img alt="01 first error" class="ipsImage ipsImage_thumbnailed" data-fileid="146702" data-unique="e7lpcy0d0" src="https://academy.hsoub.com/uploads/monthly_2024_03/01_first_error.thumb.png.f44b9f6a9c2b4d9103899f6e31dd47a2.png"> </a>
</p>

<p>
	2. السطر اﻷول من الرسالة هو التالي
</p>

<pre class="ipsCode">Uncaught TypeError: guessSubmit.addeventListener is not a function
number-game-errors.html:86:15`
</pre>

<p>
	يخبرنا الجزء الأول عن سبب الخطأ ويخبرنا الجزء الثاني عن موقع الخطأ في الشيفرة وهو السطر 86، المحرف 15 في الملف "number-game-errors.html".
</p>

<p>
	3. إن ألقينا نظرة على موقع الخطأ في السطر 86 سنجد السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1965_10" style=""><span class="pln">   guessSubmit</span><span class="pun">.</span><span class="pln">addeventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> checkGuess</span><span class="pun">);</span></pre>

<p>
	<strong>تحذير:</strong> قد لا يكون الخطأ موجودًا لديك في السطر 86 في حال كنت تستخدم موسّعًا يُشغّل خادمًا على جهازك، فقد يسبب ذلك إقحام شيفرة إضافية إلى شيفرتك، لهذا قد تشير أدوات مطوري ويب إلى مكان للخطأ مختلف عن السطر 86.
</p>

<p>
	4. ينص الخطأ على أن الشيفرة لا تمثل دالة، وهذا يعني أن الدالة التي نستدعيها لم يميزها مفسّر جافا سكريبت. وغالبًا ما يكون السبب خطأ في كتابة شيء ما. فإن لم تكن متأكدًا من الكتابة الصحيحة لتعليمة أو صياغة معينة فمن الأفضل مراجعة توثيق <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافا سكريبت</a> على موسوعة حسوب والبحث عن "addeventListener".
</p>

<p>
	5. بالعودة إلى التوثيق السابق نرى أن الخطأ كان في تهجئة اسم الدالة التي تُكتب بالشكل <code>addEventListener</code> وليس بالشكل <code>addeventListener</code> ومن مميزات <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%B5%D9%81%D8%B1-%D8%AD%D8%AA%D9%89-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81-r2046/" rel="">لغة جافا سكريبت</a> أنها حساسة لحالة الأحرف، وبالتالي تصحيح كتابة اسم الدالة سيحل المشكلة. نفّذ ذلك وتأكد من حل المشكلة.
</p>

<h2 id="-4">
	جولة ثانية على أخطاء الصياغة
</h2>

<p>
	1. احفظ التغييرات على صفحتك وحدّث المتصفح وسترى أن الخطأ قد زال.
</p>

<p>
	2. لو حاولت مجددًا تخمين رقم ثم النقر على زر اﻹرسال سترى خطأً آخر:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="146705" href="https://academy.hsoub.com/uploads/monthly_2024_03/02_second_error.png.f4da7069f5038dc4966753f41b2e440c.png" rel=""><img alt="02 second error" class="ipsImage ipsImage_thumbnailed" data-fileid="146705" data-unique="5ay57jacj" src="https://academy.hsoub.com/uploads/monthly_2024_03/02_second_error.thumb.png.88653a415a0752bfaebb2c1d2af64db3.png"> </a>
</p>

<p>
	3. الخطأ هذه المرة هو التالي:
</p>

<pre class="ipsCode">   Uncaught TypeError: can't access property "textContent", lowOrHi is null
</pre>

<p>
	قد تجد رسالة مختلفة هنا وفقًا للمتصفح الذي تستخدمه. فالرسالة السابقة هي ما يعرضه متصفح فايرفوكس، أما رسالة خطأ متصفح كروم مثلًا هي:
</p>

<pre class="ipsCode">   Uncaught TypeError: Cannot set properties of null (setting 'textContent')
</pre>

<p>
	الخطأ ذاته لكن كل متصفح يصفه بطريقة مختلفة عن اﻵخر.
</p>

<p>
	<strong>ملاحظة:</strong> لا يُعرض هذا الخطأ فور تحميل الصفحة لأنه يحدث ضمن الدالة كتلة <code>()checkGuess</code>. وكما سنرى في مقالات قادمة أن الشيفرة داخل الدوال تنفذ في سياق منفصل عن بقية الشيفرة، وبهذه الحالة لن تعمل الشيفرة ضمن الدالة ولن يقع الخطأ حتى تّنفّذ الدالة <code>()checkGuess</code> في السطر 86.
</p>

<p>
	4. ألق نظرة على الخطأ في السطر 80 وسترى الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2613_9" style=""><span class="pln">lowOrHi</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Last guess was too high!"</span><span class="pun">;</span></pre>

<p>
	5. تحاول الشيفرة في هذا السطر إسناد سلسلة نصية إلى الخاصية <code>textContent</code> للمتغير <code>lowOrHi</code> لكن اﻷمر لا ينجح لأن المتغيّر لا يتضمن ما يُفترض أنه يتضمنه. لهذا حاول أن تبحث عن ورود آخر لهذا المتغّير وستجده في السطر 49:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2613_13" style=""><span class="kwd">const</span><span class="pln"> lowOrHi </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"lowOrHi"</span><span class="pun">);</span></pre>

<p>
	نحاول في هذا السطر أن نسند إلى <code>lowOrHi</code> مرجعًا إلى عنصر من عناصر صفحة HTML، لنلقي إذًا نظرة على ما يحتويه هذا المتغير بعد هذه العملية من خلال كتابة الأمر التالي في السطر 50:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2613_15" style=""><span class="pln">   console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">lowOrHi</span><span class="pun">);</span></pre>

<p>
	تطبع هذه التعليمة قيمة المتغير <code>lowOrHi</code> على الطرفية.
</p>

<p>
	6. احفظ التغييرات وحدّث المتصفح وسترى نتيجة التعليمة <code>()console.log</code> على النحو التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="146706" href="https://academy.hsoub.com/uploads/monthly_2024_03/03_third_error.png.2c6f5fd6f30dd5e1845d4a676317f41e.png" rel=""><img alt="03 third error" class="ipsImage ipsImage_thumbnailed" data-fileid="146706" data-unique="ensonwdde" src="https://academy.hsoub.com/uploads/monthly_2024_03/03_third_error.thumb.png.4a9b138dc9e8c629c83e5a75122f74c4.png"> </a>
</p>

<p>
	إن قيمة هذا المتغير هي <code>null</code> لهذا عرض متصفح رسالة الخطأ مشيرًا إلى أن <code>lowOrHi is null</code>. لهذا هنالك خطأ بالتأكيد في السطر 49. إذ تعني القيمة <code>null</code> لاشيء أو لا قيمة، وأخفقت في النهاية عملية إسناد مرجع إلى التغيّر.
</p>

<p>
	7. لنفكر بسبب حدوث مشكلة السطر 49، إذ يحتوي هذا السطر التابع <code>()document.querySelector</code> للحصول على مرجع إلى عنصر من خلال البحث عن <a href="https://academy.hsoub.com/programming/css/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D9%85%D8%AD%D8%AF%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D9%81%D9%8A-css-r2044/" rel="">محدد CSS</a> المطابق. ولو بحثا عن العنصر المطلوب لوجدنا أنه الفقرة النصية
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7904_13" style=""><span class="pln">   </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"lowOrHi"</span><span class="tag">&gt;&lt;/p&gt;</span></pre>

<p>
	8. إذا ما نريده هو محدد صنف <a href="https://wiki.hsoub.com/CSS/Class_Selectors" rel="external">class selector</a> يبدأ سمه بنقطة <code>.</code>، لكن المحدد الذي مُرر إلى التابع <code>()querySelector</code> في السطر 49 كان بلا نقطة، وقد يكون ذلك سبب المشكلة لهذا جرّب إصلاح اﻷمر بتحويل <code>lowOrHi</code> إلى <code>lowOrHi.</code>
</p>

<p>
	9. جرّب حفظ التغييرات وتحديث الصفحة، ومن المفترض حينها أن تكون نتيجة التعليمة <code>()console.log</code> هي العنصر <code>&lt;p&gt;</code>، وهكذا نكون قد أصلحنا خطأ آخر. يمكنك اﻵن حذف السطر <code>()console.log</code> أو إبقاءه كمرجع -اﻷمر يعود إليك-.
</p>

<h3 id="-5">
	جولة ثالثة على أخطاء الصياغة
</h3>

<p>
	1. إن حاولت تجريب اللعبة مجددًا ستجد أن إصلاحاتك ناجحة وستعمل بشكل رائع حتى اللحظة التي تنهي فيها اللعبة بأن تخمّن الرقم الصحيح أوتنتهي محاولاتك.
</p>

<p>
	2. ستخفق اللعبة مجددًا في هذه المرحلة وسيظهر من جديد الخطأ الأول "TypeError: resetButton.addeventListener is not a function"، لكن مصدره هذه المرة السطر 94.
</p>

<p>
	3. بالعودة إلى هذا السطر والتدقيق فيه نجد أن الخطأ المرتكب هو نفسه الخطأ المرتكب في المرة اﻷولى، لهذا غيّر <code>addeventListener</code> إلى <code>addEventListener</code>.
</p>

<h2 id="-6">
	الخطأ المنطقي
</h2>

<p>
	يجب أن تعمل اللعبة جيدًا بعد تطبيق اﻹصلاحات السابقة جميعها، لكن بعد أن تجرب اللعبة عدة مرات ستلاحظ بلا شك أن الرقم العشوائي الذي تختاره اللعبة وعليك تخمينه هو دائما (1). وبالتأكيد لا نريد أن تكون اللعبة بهذا الشكل! لا شك إذًا أن هناك خطأ ما في منطق اللعبة لأنها لا تعيد أية أخطاء لكنها في المقابل لا تعطي النتيجة المتوقعة منها.
</p>

<p>
	1. ابحث عن المتغيّر <code>randomNumber</code> والأسطر التي ضُبط فيها بداية وستجد في السطر 45 تقريبًا التصريح عن المتغّير وإسناد قيمة له:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1965_15" style=""><span class="pln">   </span><span class="kwd">let</span><span class="pln"> randomNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span></pre>

<p>
	2. ستجد في السطر 113 الأمر الذي يوّلد الرقم العشوائي قبل كل بداية لعبة
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1965_17" style=""><span class="pln">   randomNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span></pre>

<p>
	3. للتحقق أن هذه اﻷسطر هي مصدر المشكلة، سنحاول استخدام التعليمة <code>()console.log</code>أسفل كل من السطرين السابقين كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1965_19" style=""><span class="pln">   console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">randomNumber</span><span class="pun">);</span></pre>

<p>
	4. احفظ التغييرات وحدّث المتصفح ثم جرّب أن تلعب بعض الجولات وسترى أن قيمة المتغيّر <code>randomNumber</code> تُسجّل (1) دائمًا في الطرفية.
</p>

<h3 id="-7">
	العمل على إصلاح اﻷخطاء المنطقية
</h3>

<p>
	لنتأمل كيفية عمل التابع <code>()Math.random</code> في محاولة فهم الخلل، إذ يوّلد هذا التابع رقمًا عشريًا عشوائيًا بين 0 و 1 مثل <code>0.5463723462</code>. ثم نمرر العدد العشوائي الناتج إلى تابع آخر هو <code>()Math.floor</code> والذي يقرّب قيمة العدد العشري إلى العدد الصحيح اﻷقل منه مباشرة، ثم نضيف إلى الناتج العدد 1.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1965_21" style=""><span class="typ">Math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span></pre>

<p>
	إن تقريب عدد عشري بين 0 و 1 إلى أقرب عدد صحيح أصغر منه مباشرة يعطي الرقم 0 دائمًا وعند إضافة الرقم 1 سيكون الناتج 1 دائمًا! لهذا من الواضح أن علينا ضرب العدد العشوائي بالعدد 100 للحصول على عدد عشري بين 0 و 100 ثم نقرّبه إلى أقرب عدد صحيح أصغر منه فستكون النتيجة عدد عشوائي صحيح بين 0 و 99:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1965_23" style=""><span class="typ">Math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span></pre>

<p>
	نضيف بعد ذلك الرقم 1 لنحصل على عدد بين 1 و100
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1965_25" style=""><span class="typ">Math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span></pre>

<p>
	جرّب أن تعدّل السطرين اللذان يضمان المنطق السابق ثم احفظ التغييرات وحدّث المتصفح وسترى أن اللعبة تعمل اﻵن كما نريد.
</p>

<h2 id="-8">
	أخطاء شائعة أخرى
</h2>

<p>
	ستقع في العديد من الأخطاء الشائعة عند كتابة شيفرتك، لهذا سنلقي نظرة على أهمها في الأقسام التالية.
</p>

<h3 id="syntaxerrormissingbeforestatement">
	الخطأ <code>SyntaxError: missing ; before statement</code>
</h3>

<p>
	يشير هذا الخطأ عمومًا إلى أنك أغفلت الفاصلة المنقوطة <code>;</code> في نهاية أحد أسطر الشيفرة، وقد يكون الخطأ أحيانًا أكثر غموضًا. فلو بدلنا السطر التالي ضمن الدالة <code>()checkGuess</code><br>
	 
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5860_11" style=""><span class="kwd">const</span><span class="pln"> userGuess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">guessField</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span></pre>

<p>
	إلى السطر التالي
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5860_14" style=""><span class="kwd">const</span><span class="pln"> userGuess </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">guessField</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span></pre>

<p>
	سيعرض المتصفح الخطأ السابق لأنه يعتقد بأن تحاول عمل شيء مختلف. لهذا عليك الانتباه إلى عدم الخلط بين عامل الإسناد <code>=</code> الذي يُسند قيمة إلى متغير ما، وبين عامل المساواة المنطقي <code>===</code> الذي يختبر تساوي قيمة مع قيمة أخرى ثم يعيد قيمة منطقية قيمتها صحيح <code>true</code> أو خطأ <code>false</code>.
</p>

<h3 id="-9">
	تخبرك اللعبة أنك فزت دائمًا سواء كان تخمينك صحيحًا أو خاطئًا
</h3>

<p>
	قد يكون هذا الخطأ نتيجة للخلط بين عاملي اﻹسناد والمساواة. فلو غيرنا السطر التالي ضمن الدالة <code>()chsckGuess</code>
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5860_16" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">userGuess </span><span class="pun">===</span><span class="pln"> randomNumber</span><span class="pun">)</span><span class="pln">  </span><span class="pun">{</span></pre>

<p>
	 
</p>

<p>
	إلى السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5860_18" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">userGuess </span><span class="pun">=</span><span class="pln"> randomNumber</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	سيعيد الاختبار في هذه الحالة القيمة <code>true</code> دائمًا وستخبرك اللعبة عندها أنك فائز دائمًا. انتبه لذلك!
</p>

<h3 id="syntaxerrormissingafterargumentlist">
	الخطأ <code>SyntaxError: missing ) after argument list</code>
</h3>

<p>
	هذا الخطأ بسيط نوعًا ما، ويعني عمومًا أنك أغفلت كتابة قوس الإغلاق في نهاية دالة أو تابع عند استدعائه.
</p>

<h3 id="syntaxerrormissingafterpropertyid">
	الخطأ: <code>SyntaxError: missing : after property id</code>
</h3>

<p>
	يرتبط هذا الخطأ عادة بإعداد كائن جافا سكريبت بطريقة غير صحيحة، لكننا حاولنا إظهاره هنا بتبديل هذا السطر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2613_33" style=""><span class="kwd">function</span><span class="pln"> checkGuess</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	بالسطر التالي<br>
	 
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2613_31" style=""><span class="kwd">function</span><span class="pln"> checkGuess</span><span class="pun">(</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	إذ سيعتقد المتصفح انك تحاول تمرير محتوى دالة كوسيط إلى دالة أخرى. عليك الانتباه إلى اﻷقواس جيدًا!
</p>

<h3 id="syntaxerrormissingafterfunctionbody">
	الخطأ: <code>SyntaxError: missing } after function body</code>
</h3>

<p>
	وهو خطأ بسيط يشير إلى إغفال أحد القوسين المعقوصين في بنية دالة أو كتلة شرطية، يمكنك توليد هذا الخطأ بحذف القوس المعقوص من نهاية<br>
	الدالة <code>()checkGuess</code>
</p>

<h3 id="syntaxerrorexpectedexpressiongotstringsyntaxerrorunterminatedstringliteral">
	الخطأ: <code>'*SyntaxError: expected expression, got '*string</code> أو <code>SyntaxError: unterminated string literal</code>
</h3>

<p>
	تعني هذه اﻷخطاء عمومًا أنك أغفلت أحد علامات التنصيص التي تغلق سلسلة نصية أو تبدؤها. ففي الخطأ اﻷول يستبدل المتصفح القيمة string بالقيمة غير المتوقعة التي وجدها بدلًا من إشارة التنصيص في بداية السلسلة النصية. أما الخطأ الثاني فيعني أنك لم تنهي السلسلة النصية بإشارة تنصيص.
</p>

<p>
	وفي جميع اﻷخطاء التي قد تواجهك، فكّر بالطريقة التي اتبعناها في أمثلتنا لحل اﻷخطاء. فعندما يقع الخطأ، انتقل إلى السطر الذي وقع فيه والذي تشير إليه طرفية أدوات مطوري ويب وحاول أن تتفحص ما يمكن أن يكون خاطئًا. وتذكر دائمًا أنه ليس من الضرورة أن تكون اﻷخطاء في نفس السطر، وأن الخطأ قد لا ينتج بالضرورة عن نفس اﻷسباب التي تحدثنا عنها في مقالنا.
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="487" id="ips_uid_7904_6" src="https://academy.hsoub.com/applications/core/interface/index.html" title="كيفية التعامل مع الأخطاء البرمجية" width="866" data-embed-src="https://www.youtube.com/embed/Pgje6nWuDkg"></iframe>
</p>

<h2 id="-10">
	الخلاصة
</h2>

<p>
	هكذا نكون قد تعرفنا على أساسيات تتبع اﻷخطاء البسيطة في جافا سكريبت. وتذكر أنه ليس من السهل دائمًا اكتشاف الخطأ في الشيفرة البرمجية، لكن ما قدمناه في هذه المقالة قد يوفر عليك ساعات من العناء ويسرّع وتيرة اكتشافك اﻷسباب المحتملة للأخطاء وخاصة في بداية رحلتك في <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>.
</p>

<p>
	ترجمة -وبتصرف لمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong" rel="external nofollow">What went wrong troubleshooting JavaScript</a>
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%AC%D8%B1%D8%A8%D8%AA%D9%83-%D8%A7%EF%BB%B7%D9%88%D9%84%D9%89-%D9%85%D8%B9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2273/" rel="">تجربتك اﻷولى مع جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%A8%D8%A7%D8%AF%D8%A6-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D8%AA%D8%B3%D9%82%D8%A9-%D9%88%D9%85%D9%81%D9%87%D9%88%D9%85%D8%A9-r2178/" rel="">مبادئ كتابة جافا سكريبت متسقة ومفهومة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1342/" rel="">كيفية التعامل مع الأخطاء البرمجية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B2%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1245/" rel="">الزلات البرمجية والأخطاء في جافاسكريبت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2274</guid><pubDate>Thu, 21 Mar 2024 12:02:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62D;&#x644;&#x642;&#x627;&#x62A; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2277/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_03/879659041_.png.afb016f300c58a4fa171946e37c9e4dc.png" /></p>
<p>
	تظهر أهمية لغات البرمجة في إنجاز مهام مكررة وبسرعة مثل الحسابات المتعددة، أو في الحالات التي ينبغي فيها إنجاز الكثير من اﻷعمال المتشابهة. لهذا سنخصص هذا المقال للحديث عن الحلقات في جافا سكريبت التي تعالج تلك اﻷمور. ننصحك قبل أن تبدأ العمل معنا في هذه السلسلة أن تطلع على:
</p>

<ol>
	<li>
		أساسيات علوم الحاسب
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/html/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-html-r1687/" rel="">أساسيات HTML</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/css/%D8%AA%D8%B9%D8%B1%D9%91%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-css-r70/" rel="">أساسيات عمل CSS</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1689/" rel="">أساسيات لغة جافا سكريبت</a>
	</li>
</ol>

<h2 id="-1">
	ما هي فائدة الحلقات؟
</h2>

<p>
	تتمحور فكرة الحلقة على تكرار الشيء ذاته باستمرار. قد تختلف الشيفرة قليلًا في كل جولة أو قد تبقى الشيفرة كما هي وتتغير قيمة المتغيرات فيها.
</p>

<h3 id="-2">
	مثال عن شيفرة تستخدم الحلقات
</h3>

<p>
	لنفرض أنك تريد رسم 100 دائرة عشوائية ضمن العنصر <code>&lt;canvas&gt;</code> انقر الزر "<strong>Update</strong>" لتنفيذ الشيفرة مرة تلو اﻷخرى لترى مجموعات مختلفة من الدوائر):
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="300" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/QWPEzXR?default-tab=result" style="width: 100%;" title="Looping code1">See the Pen Looping code1 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<p>
	إليك شيفرة جافا سكريبت التي تنفّذ المطلوب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_8" style=""><span class="kwd">const</span><span class="pln"> btn </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"button"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"canvas"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">"2d"</span><span class="pun">);</span><span class="pln">

document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"DOMContentLoaded"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  canvas</span><span class="pun">.</span><span class="pln">width </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">clientWidth</span><span class="pun">;</span><span class="pln">
  canvas</span><span class="pun">.</span><span class="pln">height </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">clientHeight</span><span class="pun">;</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> random</span><span class="pun">(</span><span class="pln">number</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> number</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  ctx</span><span class="pun">.</span><span class="pln">clearRect</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">width</span><span class="pun">,</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">height</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">let</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgba(255,0,0,0.5)"</span><span class="pun">;</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">arc</span><span class="pun">(</span><span class="pln">
      random</span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">width</span><span class="pun">),</span><span class="pln">
      random</span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">height</span><span class="pun">),</span><span class="pln">
      random</span><span class="pun">(</span><span class="lit">50</span><span class="pun">),</span><span class="pln">
      </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
      </span><span class="lit">2</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

btn</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> draw</span><span class="pun">);</span></pre>

<h3 id="-3">
	مع أو بدون حلقة
</h3>

<p>
	ليس عليك فهم الشيفرة بأكملها اﻵن، لكن ألق نظرة على الجزء الذي يرسم 100 دائرة في الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_10" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">let</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln">
  ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgba(255,0,0,0.5)"</span><span class="pun">;</span><span class="pln">
  ctx</span><span class="pun">.</span><span class="pln">arc</span><span class="pun">(</span><span class="pln">
    random</span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">width</span><span class="pun">),</span><span class="pln">
    random</span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">height</span><span class="pun">),</span><span class="pln">
    random</span><span class="pun">(</span><span class="lit">50</span><span class="pun">),</span><span class="pln">
    </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
    </span><span class="lit">2</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">);</span><span class="pln">
  ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
	<li>
		تُعيد الدالة <code>random</code> المعرّفة سابقًا رقمًا صحيحًا محصورًا بين الصفر و <code>1-x</code>. أما الفكرة العامة فهي أننا نستخدم حلقة لتكرار الشيفرة السابقة 100 مرة، وكل مرة ترسم الشيفرة دائرة في مكان عشوائي من الصفحة. وتبقى كمية الشيفرة اللازمة لرسم الدائرة نفسها سواءً رسمنا 10 أو 100 أو 1000 دائرة، وما يتغير فقط هو عدد مرات التكرار، ولو لم نستخدم الحلقة كان لا بد من كتابة الشيفرة التالية في كل مرة نريد رسم دائرة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_12" style=""><span class="pln">ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln">
ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgba(255,0,0,0.5)"</span><span class="pun">;</span><span class="pln">
ctx</span><span class="pun">.</span><span class="pln">arc</span><span class="pun">(</span><span class="pln">
  random</span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">width</span><span class="pun">),</span><span class="pln">
  random</span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">height</span><span class="pun">),</span><span class="pln">
  random</span><span class="pun">(</span><span class="lit">50</span><span class="pun">),</span><span class="pln">
  </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI</span><span class="pun">,</span><span class="pln">
</span><span class="pun">);</span><span class="pln">
ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span></pre>

<p>
	وسيكون الأمر مملًا وصعب التنقيح والصيانة.
</p>

<h2 id="-4">
	استخدام الحلقات للتنقل ضمن مجموعات
</h2>

<p>
	غالبًا ما تستخدم الحلقة للتنقل بين مجموعة من العناصر لتنفيذ أمر ما على كل عنصر. ومن اﻷمثلة على المجموعات نجد <a href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%87%D9%85-%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r555/" rel="">المصفوفات</a>، إضافة إلى بُنى أخرى في جافا سكريبت مثل <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%86%D9%88%D8%B9-map-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-%D9%88%D8%A7%D9%84%D9%86%D9%88%D8%B9-set-%D8%A7%D9%84%D8%A3%D8%B7%D9%82%D9%85-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r821/" rel="">المجموعات Sets و الخرائط Maps</a>.
</p>

<h3 id="forof">
	الحلقة <code>for...of</code>
</h3>

<p>
	تعد هذه الحلقة أساسية في النقل ضمن عناصر مجموعة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_14" style=""><span class="kwd">const</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Leopard"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Serval"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jaguar"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Tiger"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Caracal"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Lion"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> cat </span><span class="kwd">of</span><span class="pln"> cats</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">cat</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	في مثالنا هذا، تنص العبارة البرمجية <code>for (const cat of cats)</code> على ما يلي:
</p>

<ol>
	<li>
		إذا كانت <code>cats</code> مجموعة من العناصر استخرج العنصر اﻷول منها.
	</li>
	<li>
		إسناد قيمة هذا العنصر إلى المتغير <code>cat</code> ومن ثم نفّذ الشيفرة الموجودة ضمن القوسين المعقوصين <code>{}</code>.
	</li>
	<li>
		استخراج العنصر التالي وكرر الخطوة 2 حتى تصل إلى نهاية المجموعة.
	</li>
</ol>

<h3 id="filtermap">
	التابعين <code>filter</code> و <code>map</code>
</h3>

<p>
	تقدّم جافا سكريبت حلقات مخصصة أيضًا للتنقل ضمن المجموعات، وسنشير إلى اثنتين منهما. الحلقة اﻷولى يمثلها التابع <code>()map</code> الذي ينفّذ شيئًا محددًا على كل عناصر المجموعة ويعيد مجموعة جديدة تضم العناصر المتغيرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_19" style=""><span class="kwd">function</span><span class="pln"> toUpper</span><span class="pun">(</span><span class="pln">string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> string</span><span class="pun">.</span><span class="pln">toUpperCase</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Leopard"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Serval"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jaguar"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Tiger"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Caracal"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Lion"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> upperCats </span><span class="pun">=</span><span class="pln"> cats</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">toUpper</span><span class="pun">);</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">upperCats</span><span class="pun">);</span><span class="pln">
</span><span class="com">// [ "LEOPARD", "SERVAL", "JAGUAR", "TIGER", "CARACAL", "LION" ]</span></pre>

<p>
	مررنا في مثالنا السابق دالة إلى التابع <code>()cats.map</code> الذي يستدعيها مرة لكل عنصر من عناصر المصفوفة، ثم يمرر هذا العنصر إلى الدالة ويجمّع القيم العائدة عنها بعد كل استدعاء ضمن مصفوفة جديدة تحتوى عناصر المصفوفة القديمة بعد تغيير حالة أحرف هذه العناصر.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_21" style=""><span class="pun">[</span><span class="pln"> </span><span class="str">"LEOPARD"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"SERVAL"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"JAGUAR"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"TIGER"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"CARACAL"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"LION"</span><span class="pln"> </span><span class="pun">]</span></pre>

<p>
	أما الحلقة الثانية فيقدمها التابع <code>()filter</code> الذي يختبر كل عنصر من عناصر المجموعة ويعيد مصفوفة جديدة تضم العناصر التي تحقق شرطًا معينًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_23" style=""><span class="kwd">function</span><span class="pln"> lCat</span><span class="pun">(</span><span class="pln">cat</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> cat</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="str">"L"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Leopard"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Serval"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jaguar"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Tiger"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Caracal"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Lion"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> filtered </span><span class="pun">=</span><span class="pln"> cats</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">lCat</span><span class="pun">);</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">filtered</span><span class="pun">);</span><span class="pln">
</span><span class="com">// [ "Leopard", "Lion" ]</span></pre>

<p>
	يبدو الأمر مشابهًا للتابع <code>()map</code>، ما عدا أن القيمة التي تعيدها الدالة التي نمررها هي قيمة منطقية. فإذا كانت <code>true</code> يُضمّن العنصر في المصفوفة الجديدة وإلا لن يُضمَّن. أما وظيفة الدالة في هذا المثال فهي اختبار العناصر التي تبدأ بالحرف "L"، لذا ستكون النتيجة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_25" style=""><span class="pun">[</span><span class="pln"> </span><span class="str">"Leopard"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Lion"</span><span class="pln"> </span><span class="pun">]</span></pre>

<p>
	ولاحظ كيف يُستخدم التابعان <code>()map</code> و <code>()filter</code> في بعض اﻷحيان مع دوال وهذا ما سندرسه لاحقًا. وباستخدام الدوال يمكن إعادة كتابة الشيفرة السابقة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_27" style=""><span class="kwd">const</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Leopard"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Serval"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jaguar"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Tiger"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Caracal"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Lion"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> filtered </span><span class="pun">=</span><span class="pln"> cats</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">cat</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> cat</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="str">"L"</span><span class="pun">));</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">filtered</span><span class="pun">);</span><span class="pln">
</span><span class="com">// [ "Leopard", "Lion" ]</span></pre>

<h2 id="for">
	حلقة <code>for</code>المعيارية
</h2>

<p>
	في مثالنا السابق الذي يدور حول رسم دوائر، لم يكن عليك التنقل بين عناصر مجموعة بل تكرار نفس الشيفرة 100 مرة. عليك في حالات كهذه استخدام الحلقة <code>for</code> التي لها الصياغة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_29" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">initializer</span><span class="pun">;</span><span class="pln"> condition</span><span class="pun">;</span><span class="pln"> final</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// code to run</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لدينا هنا:
</p>

<ol>
	<li>
		الكلمة المحجوزة <code>for</code>.
	</li>
	<li>
		ضمن القوسين التاليين ثلاثة عناصر تفصل بينها فاصلة:
		<ul>
			<li>
				<strong>مهييء initializer</strong>: وهو متغيّر له قيمة عددية محددة سوف تزداد لتعدد المرات التي تثنفَّذ فيها الحلقة. ويُشار إليها أحيانًا بالعداد.
			</li>
			<li>
				<strong>شرط condition</strong>: ويحدد متى ستنتهي الحلقة. وهو عادة عبارة برمجية تستخدم عامل موازنة وتختبر إذا ما تحقق الشرط أم لا.
			</li>
			<li>
				<strong>عبارة إنهاء final-expression</strong>:وتُنفّذ أو تُقيَّّم في كل مرة تنهي الحلقة أحد التكرارات. وتُستخدم عادة لتزيد (أو تنقص) العداد لتقربه من النقطة التي لا يتحقق بعدها الشرط (العنصر الثاني).
			</li>
		</ul>
	</li>
	<li>
		أقواس معقوصة تضم كتلة من الشيفرة التي تُنفَّذ في كل تكرار للحلقة.
	</li>
</ol>

<h3 id="for-1">
	مثال عن حلقة for: حساب مربعات أعداد
</h3>

<p>
	لنلق نظرة على مثال حقيقي لنتصوّر اﻷمر بوضوح أكثر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_33" style=""><span class="kwd">const</span><span class="pln"> results </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"#results"</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> calculate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">let</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> newResult </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">i</span><span class="pun">}</span><span class="pln"> x $</span><span class="pun">{</span><span class="pln">i</span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">i </span><span class="pun">*</span><span class="pln"> i</span><span class="pun">}`;</span><span class="pln">
    results</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">newResult</span><span class="pun">}</span><span class="pln">\n</span><span class="pun">`;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  results</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">+=</span><span class="pln"> </span><span class="str">"\nFinished!"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> calculateBtn </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"#calculate"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> clearBtn </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"#clear"</span><span class="pun">);</span><span class="pln">

calculateBtn</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> calculate</span><span class="pun">);</span><span class="pln">
clearBtn</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">results</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">));</span></pre>

<p>
	تُعطي الشيفرة السابقة الخرج التالي:
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="300" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/ZEZOwYb?default-tab=result" style="width: 100%;" title="Looping code2">See the Pen Looping code2 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<p>
	تحسب الشيفرة السابقة مربعات الأعداد من 1 إلى 9 وتطبع النتيجة، وتُستخدم الحلقة <code>for</code> كأساس لإجراء الحسابات. لنحلل بشيء من التفصيل العبارة<br>
	<code>for (let i = 1; i &lt; 10; i++)</code>:
</p>

<ol>
	<li>
		المهيء (<code>let i = 1</code>) يبدأ العداد <code>i</code> من القيمة 1. ولاحظ ضرورة استخدام التعليمة <code>let</code> لأننا نعيد إسناد قيمة له عند كل تكرار.
	</li>
	<li>
		الشرط (<code>i &lt; 10</code>) ويعني أن تستمر الحلقة في تكرار نفسها طالما أن <code>i</code> أصغر من <code>10</code>.
	</li>
	<li>
		عبارة اﻹنهاء (<code>++i</code>) وتضيف واحد إلى العداد عند إتمام كل تكرار. نحسب داخل الحلقة مربع القيمة الحالية للمتغير <code>i</code> بالشكل :<code>i*i</code>، وننشئ عبارة نصية تضم العملية التي أجريناها ونتيجتها. كما نضيف السلسلة <code>n\</code> إلى آخر السلسلة النصية كي تُطبع نتيجة التكرار التالي على سطر جديد. وما سيحدث اﻵن هو:
	</li>
	<li>
		خلال التكرار الأول ستكون <code>i=1</code>، وستكون النتيجة <code>1x1=1</code>.
	</li>
	<li>
		خلال التكرار الثاني ستكون <code>i=2</code>، وستكون النتيجة <code>2x2=4</code>.
	</li>
	<li>
		تستمر الحلقة بهذا الشكل.
	</li>
	<li>
		عندما تصبح <code>i=10</code> تتوقف الحلقة عند تنفيذ الشيفرة ما داخل القوسين المعقوصين وتنتقل إلى الشفرة التي تلي الحلقة وتطبع الرسالة <code>!finished</code> على سطر جديد.
	</li>
</ol>

<h3 id="for-2">
	التنقل بين عناصر مجموعة باستخدام الحلقة <code>for</code>
</h3>

<p>
	بإمكانك استخدام الحلقة <code>for</code> للتنقل بين عناصر مجموعة بدلًا من <code>for...of</code>. لنعد إلى مثال <code>for...of</code> السابق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_31" style=""><span class="kwd">const</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Leopard"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Serval"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jaguar"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Tiger"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Caracal"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Lion"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> cat </span><span class="kwd">of</span><span class="pln"> cats</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">cat</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنكتب الشيفرة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_35" style=""><span class="kwd">const</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Leopard"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Serval"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jaguar"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Tiger"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Caracal"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Lion"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">let</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> cats</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">cats</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نبدأ هذه الحلقة عند قيمة <code>i=0</code> وننهيها عندما تصل قيمة <code>i</code> إلى طول المصفوفة. ونستخدم <code>i</code> ضمن الحلقة للوصول إلى كل عنصر من عناصرها. ستعمل الحلقة جيدًا وقد استخدمت قبل ظهور وكانت الطريقة المعيارية للتنقل بين عناصر مصفوفة، لكن قد تزداد الفرصة عند استخدامها إلى ظهور ثغرات في الشيفرة مثل:
</p>

<ul>
	<li>
		أن تبدأ <code>i</code> من القيمة <code>1</code> وتنسى أن تعداد المصفوفات يبدأ من <code>0</code>.
	</li>
	<li>
		قد تنهي الحلقة عند <code>i&lt;=cats.length</code> وتنسى أن نآخر دليل في المصفوفة هو <code>length-1</code>. لأسباب كهذه، يُفضّل استخدام <code>for...of</code> إن استطعت ذلك، لكنك ستحتاج في بعض اﻷحيان إلى <code>for</code> عند النقل بين عناصر مصفوفة. فإن أردت مثلًا طباعة رسالة تضم قائمة بأسماء القطط باستخدام الشيفرة التالية:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_37" style=""><span class="kwd">const</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Pete"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Biggles"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jasmine"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">let</span><span class="pln"> myFavoriteCats </span><span class="pun">=</span><span class="pln"> </span><span class="str">"My cats are called "</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> cat </span><span class="kwd">of</span><span class="pln"> cats</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  myFavoriteCats </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">cat</span><span class="pun">},</span><span class="pln"> </span><span class="pun">`;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">myFavoriteCats</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "My cats are called Pete, Biggles, Jasmine, "</span></pre>

<p>
	لن تكون النتيجة (من ناحية تكوين الجملة في اﻹنكليزية) مصاغة بالكل الصحيح:
</p>

<pre class="ipsCode">My cats are called Pete, Biggles, Jasmine,
</pre>

<p>
	لهذا يجب أن تتعامل الحلقة مع آخر اسم بشكل مختلف حتى تكون النتيجة بالشكل:
</p>

<pre class="ipsCode">My cats are called Pete, Biggles, and Jasmine.
</pre>

<p>
	ولفعل ذلك، ينبغي أن نعرف دليل آخر عنصر ونحتاج عندها إلى الحلقة <code>for</code> لتفحّص قيمة <code>i</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_39" style=""><span class="kwd">const</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Pete"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Biggles"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jasmine"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">let</span><span class="pln"> myFavoriteCats </span><span class="pun">=</span><span class="pln"> </span><span class="str">"My cats are called "</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">let</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> cats</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">===</span><span class="pln"> cats</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// We are at the end of the array</span><span class="pln">
    myFavoriteCats </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">and $</span><span class="pun">{</span><span class="pln">cats</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]}.`;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    myFavoriteCats </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">cats</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]},</span><span class="pln"> </span><span class="pun">`;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">myFavoriteCats</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "My cats are called Pete, Biggles, and Jasmine."</span></pre>

<h2 id="break">
	الخروج من الحلقة باستخدام التعليمة <code>break</code>
</h2>

<p>
	إن أردت الخروج من حلقة باكرًا قبل انتهاء جميع التكرارات، استخدم التعليمة <code>break</code> التي رأيناها في مقال <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B9%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%88%D8%A7%D8%AA%D8%AE%D8%A7%D8%B0-%D8%A7%D9%84%D9%82%D8%B1%D8%A7%D8%B1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2271/" rel="">العبارات الشرطية</a> عند التعامل مع البنية <code>switch</code>، إذ تنهي التعليمة <code>break</code> البنية <code>switch</code> في الحالة <code>case</code> التي تحقق تطابقًا مع الشرط. يتكرر اﻷمر ذاته مع الحلقات، إذ يمكن إنهاء الحلقة مباشرة باستخدام <code>break</code> وجعل المتصفح يقفز إلى الشيفرة التي تلي الحلقة. فلو أردنا مثلًا تطبيقًا للبحث عبر مصفوفة تضم جهات اتصال وأرقام هواتف ونريد فقط رقمًا محددًا، سنحتاج إلى شيفرة HTML تضم عنصر إدخال نصي <code>&lt;input&gt;</code> لإدخال الرقم الذي نبحث عنه وزر <code>&lt;button&gt;</code> لتنفيذ العملية وفقرة نصية <code>&lt;p&gt;</code> لعرض النتيجة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5008_43" style=""><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"search"</span><span class="tag">&gt;</span><span class="pln">Search by contact name: </span><span class="tag">&lt;/label&gt;</span><span class="pln">
</span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"search"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
</span><span class="tag">&lt;button&gt;</span><span class="pln">Search</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;p&gt;&lt;/p&gt;</span></pre>

<p>
	ستكون شيفرة جافا سكريبت كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_45" style=""><span class="kwd">const</span><span class="pln"> contacts </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="str">"Chris:2232322"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Sarah:3453456"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Bill:7654322"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Mary:9998769"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Dianne:9384975"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> para </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> input </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"input"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> btn </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"button"</span><span class="pun">);</span><span class="pln">

btn</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> searchName </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">.</span><span class="pln">value</span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">();</span><span class="pln">
  input</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  input</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
  para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> contact </span><span class="kwd">of</span><span class="pln"> contacts</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> splitContact </span><span class="pun">=</span><span class="pln"> contact</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">":"</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">splitContact</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">toLowerCase</span><span class="pun">()</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> searchName</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">splitContact</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]}</span><span class="str">'</span><span class="pln">s number is $</span><span class="pun">{</span><span class="pln">splitContact</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]}.`;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">===</span><span class="pln"> </span><span class="str">""</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Contact not found."</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="300" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/poBbGJo?default-tab=result" style="width: 100%;" title="Looping code3">See the Pen Looping code3 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<ol>
	<li>
		<p>
			نعرّف أولًا بعض المتغيّرات منها مصفوفة جهات الاتصال المؤلفة من عناصر نصيّة تحتوي على اسم ورقم هاتف تفصل بينهما نقطتان فوق بعضهما :
		</p>
	</li>
	<li>
		<p>
			نربط بعدها مترصّد أحداث إلى الزر <code>btn</code> لتشغيل الشيفرة التي تنفّذ البحث وتعيد النتيجة عند النقر عليه.
		</p>
	</li>
	<li>
		<p>
			نخزّن القيم المدخلة إلى مربع اﻹدخال في المتغيّر <code>searchName</code> قبل أن نفرّغه ونعيد إليه تركيز الدخل من جديد. ولاحظ استخدام التابع <code>()toLowerCase</code> كي يحول النص المدخل إلى حروف صغيرة وبالتالي لن يكون البحث حساسًا لحالة الحروف.
		</p>
	</li>
	<li>
		<p>
			نأتي إلى الجزء الذي يضم الحلقة <code>for...of</code>:
		</p>
	</li>
	<li>
		<p>
			نفصل بداية جهة الاتصال عند النقطتين المتعامدتين ونخزّن القيمتين الناتجتين عن عملية الفصل في مصفوفة تُدعى .
		</p>
	</li>
	<li>
		<p>
			نستخدم بعد ذلك عبارة شرطية لاختبار إن كانت قيمة <code>splitContact[0]</code> (وتمثّل اسم المستخدم المحوّل إلى حروف صغيرة) متطابقة مع القيمة المخزّنة في المتغير<code>searchName</code> فإن وجد التطابق نعرض في الفقرة النصية الرقم الموافق ثم نستخدم <code>break</code> ﻹنهاء الحلقة.
		</p>
	</li>
	<li>
		<p>
			إن لم نجد جهة اتصال مطابقة للبحث لن تظهر أي قيمة في الفقرة النصية، لهذا نضع ضمنها النص "Contact not found." بمعني أننا لم نجد جهة الاتصال المطلوبة. <strong>ملاحظة:</strong> بإمكانك الاطلاع على <a href="https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/loops/contact-search.html" rel="external nofollow">الشيفرة المصدرية الكاملة</a> لهذا المثال على جيت-هب، وتستطيع <a href="https://mdn.github.io/learning-area/javascript/building-blocks/loops/contact-search.html" rel="external nofollow">تجربته مباشرة</a> كذلك.
		</p>
	</li>
</ol>

<h2 id="continue">
	تخطي أحد التكرارات باستخدام <code>continue</code>
</h2>

<p>
	تعمل التعليمة <code>continue</code> بشكل مشابه للتعليمة <code>break</code> لكنها تتخطى التكرار الحالي إلى التكرار التالي بدلًا من الخروج من الحلقة نهائيًا. لنلق نظرة على مثال آخر يأخذ عدة مدخلات ويعيد فقط اﻷعداد التي تمثل مرّبعات ﻷعداد صحيحة. إليك أولًا شيفرة HTML:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5008_47" style=""><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"number"</span><span class="tag">&gt;</span><span class="pln">Enter number: </span><span class="tag">&lt;/label&gt;</span><span class="pln">
</span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"number"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"number"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
</span><span class="tag">&lt;button&gt;</span><span class="pln">Generate integer squares</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;p&gt;</span><span class="pln">Output:</span><span class="tag">&lt;/p&gt;</span></pre>

<p>
	وهذه شيفرة جافا سكريبت اللازمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_49" style=""><span class="kwd">const</span><span class="pln"> para </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> input </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"input"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> btn </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"button"</span><span class="pun">);</span><span class="pln">

btn</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Output: "</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> num </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">.</span><span class="pln">value</span><span class="pun">;</span><span class="pln">
  input</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  input</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">let</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> num</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> sqRoot </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">sqrt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">(</span><span class="pln">sqRoot</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!==</span><span class="pln"> sqRoot</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">continue</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">i</span><span class="pun">}</span><span class="pln"> </span><span class="pun">`;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	وهذا هو خرج البرنامج:
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="300" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/poBbGgv?default-tab=result" style="width: 100%;" title="Looping Code4">See the Pen Looping Code4 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<ol>
	<li>
		يجب أن يكون الدخل في هذه الحالة عددًا (المتغير <code>num</code>)، وتبدأ الحلقة من 1 (لأن 0 لا يهمنا في هذا التطبيق). هنالك أيضًا شرط للخروج من الحلقة وهو أن يكون العداد أكبر من العدد المدخل <code>num</code>، ويزداد العداد بمقدار 1 في كل تكرار.
	</li>
	<li>
		نحسب الجذر التربيعي لكل عدد داخل الحلقة ياستخدام التابع <code>(i)Math.sqrt</code>ومن ثم نتحقق أنه عدد صحيح بمقارنته مع نفسه عند تقريبه إلى أصغر عدد صحيح باستخدام التابع <code>()Math.floor</code>.
	</li>
	<li>
		إن لم يتساوى الجذر التربيعي والقيمة المقرّبة له (<code>==!</code>) فهذا يعني أن الجذر التربيعي ليس عددًا صحيحًا ولن يكون مهمًا بالنسبة لنا لهذا نستخدم <code>continue</code> في هذه الحالة للانتقال إلى العدد التالي دون أن نسجّل هذا العدد.
	</li>
	<li>
		إن كان الجذر التربيعي صحيحًا نتخطى الكتلة <code>if</code> كليًا ولن تُنفَّذ التعليمة <code>continue</code> بل نضيف قيمة <code>i</code> وبعده مسافة فارغة إلى محتوى الفقرة النصية.
	</li>
</ol>

<p>
	<strong>ملاحظة:</strong> بإمكانك الاطلاع على <a href="https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/loops/integer-squares.html" rel="external nofollow">الشيفرة المصدرية الكاملة</a> لهذا المثال على جيت-هب، وتستطيع <a href="https://mdn.github.io/learning-area/javascript/building-blocks/loops/integer-squares.html" rel="external nofollow">تجربته مباشرة</a> كذلك.
</p>

<h2 id="whiledowhile">
	الحلقتين <code>while</code> و <code>do...while</code>
</h2>

<p>
	إن الحلقة <code>for</code> ليست الوحيدة في جافا سكريبت، وعلى الرغم أنك لن تحتاج إلى معرفة كل أنواع الحلقات حاليًا، من الجيد الاطلاع على بعضها كي تميّز وجه الشبه والاختلاف بينها. لنلق نظرة بداية على الحلقة <code>while</code> التي لها الصياغة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_51" style=""><span class="pln">initializer
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">condition</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// code to run</span><span class="pln">

  final</span><span class="pun">-</span><span class="pln">expression
</span><span class="pun">}</span></pre>

<p>
	تعمل الحلقة بشكل مشابه للحلقة <code>for</code>، إلا أن المهيّء يُضبط قبل الحلقة وعبارة الإنهاء موجودة ضمن الحلقة بعد الشيفرة التي تُنفَّذ عند تحقق الشرط بدلًا من وجودهما بين القوسين التاليين للتعليمة <code>while</code> إلى جانب عبارة الشرط. وكما نرى، فإن العناصر الثلاث السابقة الموجودة في حلقة <code>for</code> موجودة أيضًا في الحلقة <code>while</code> وبنفس الترتيب لأنك تحتاج إلى المهيئ قبل أن تختبر صحة الشرط ثم تُنفَّذ عبارة اﻹنهاء عند انتهاء تنفيذ شيفرة الحلقة التي تستمر طالما أن الشرط محقق.
</p>

<p>
	نحاول تاليًا إعادة كتابة شيفرة مثالنا السابق عن القطط لكن باستخدام الحلقة <code>while</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_53" style=""><span class="kwd">const</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Pete"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Biggles"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jasmine"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">let</span><span class="pln"> myFavoriteCats </span><span class="pun">=</span><span class="pln"> </span><span class="str">"My cats are called "</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">let</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> cats</span><span class="pun">.</span><span class="pln">length</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">===</span><span class="pln"> cats</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    myFavoriteCats </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">and $</span><span class="pun">{</span><span class="pln">cats</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]}.`;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    myFavoriteCats </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">cats</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]},</span><span class="pln"> </span><span class="pun">`;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  i</span><span class="pun">++;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">myFavoriteCats</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "My cats are called Pete, Biggles, and Jasmine."</span></pre>

<p>
	وبالنسبة للحلقة <code>do...while</code>، فهي مشابهة جدًا للحلقة <code>while</code> مع بعض التغييرات في الصياغة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_55" style=""><span class="pln">initializer
</span><span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// code to run</span><span class="pln">

  final</span><span class="pun">-</span><span class="pln">expression
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">condition</span><span class="pun">)</span></pre>

<p>
	نلاحظ في هذه الحالة أن المهيئ يأتي أولًا قبل بداية الحلقة ثم الكلمة المحجوزة <code>do</code> يتبعها قوسين معقوصين يضمان الشيفرة التي يجب تنفيذها ثم عبارة اﻹنهاء ثم يأتي بعد القوسين المعقوصين مباشرة التعليمة <code>while</code> يليها الشرط. إن الفرق الرئيسي بين الحلقتين السابقتين هو أن الشيفرة ضمن الحلقة <code>do...while</code> ستُنفَّذ على اﻷقل مرة واحدة قبل اختبار صحة الشرط. إي تُنفَّذ الشيفرة وبعدها يُختبر الشرط لتحديد الحاجة إلى تنفيذ الشيفرة مجددًا. أما في <code>while</code>و <code>for</code>يُختبر الشرط أولًا. لنحاول تاليًا إعادة كتابة شيفرة مثالنا السابق عن القطط باستخدام الحلقة <code>do...while</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_57" style=""><span class="kwd">const</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Pete"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Biggles"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jasmine"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">let</span><span class="pln"> myFavoriteCats </span><span class="pun">=</span><span class="pln"> </span><span class="str">"My cats are called "</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">let</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">===</span><span class="pln"> cats</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    myFavoriteCats </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">and $</span><span class="pun">{</span><span class="pln">cats</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]}.`;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    myFavoriteCats </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">cats</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]},</span><span class="pln"> </span><span class="pun">`;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  i</span><span class="pun">++;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> cats</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">myFavoriteCats</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "My cats are called Pete, Biggles, and Jasmine."</span></pre>

<p>
	<strong>تحذير:</strong> يجب التأكد في حلقات <code>while</code> و <code>do...while</code> وجميع الحلقات اﻷخرى من زيادة أو إنقاص المهيئ تبعًا للحالة حتى يصبح الشرط في مرحلة ما غير محقق وتنتهي الحلقة وإلا ستستمر الحلقة إلى ما لا نهاية أو سيوقفها المتصفح أو ستنهار الشيفرة. تُدعى هذه الحالة -<strong>حلقة لانهائية infinite loop</strong>-.
</p>

<h2 id="-5">
	تطبيق عملي: إبدأ العد التنازلي!
</h2>

<p>
	نطلب إليك في هذا التمرين طباعة عد تنازلي من 10 إلى 0، ونريد تحديدًا:
</p>

<ul>
	<li>
		حلقة من 10 إلى 0، وقد زوّدناك بالمهيئ <code>;let i = 10</code>.
	</li>
	<li>
		إنشاء فقرة نصية جديدة في كل تكرار للحلقة وإلحاقها بعنصر الخرج <code>&lt;div&gt;</code> الذي نختاره باستخدام اﻷمر :
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_59" style=""><span class="pln">  </span><span class="kwd">const</span><span class="pln"> output </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.output'</span><span class="pun">);</span></pre>

<p>
	وقد زوّدناك في التعليقات بثلاث أسطر من الشيفرة يجب استخدامها ضمن الحلقة:
</p>

<ul>
	<li>
		<p>
			السطر<code>;const para = document.createElement('p')</code> الذي يُنشىء فقرة نصية جديدة.
		</p>
	</li>
	<li>
		<p>
			السطر <code>;output.appendChild(para)</code> الذي يُلحق الفقرة النصية بالعنصر <code>&lt;div&gt;</code>.
		</p>
	</li>
	<li>
		<p>
			السطر <code>=para.textContent</code>الذي يجعل محتوى الفقرة ما تضعه من الناحية اليمنى للمساواة.
		</p>
	</li>
	<li>
		<p>
			يتطلب كل تكرار نصًا مختلفًا يوضع ضمن الفقرة النصية وفقًا للعدد الذي وصلنا إليه، لذا تحتاج عبارة شرطية وعدة عبارات <code>=para.textContent</code>:
		</p>
	</li>
	<li>
		<p>
			إن كان العدد هو 10 يجب طباعة "Countdown 10".
		</p>
	</li>
	<li>
		<p>
			إن كان العدد هو 0 يجب طباعة "!Blast off".
		</p>
	</li>
	<li>
		<p>
			يُطبع أي عدد آخر كما هو.
		</p>
	</li>
	<li>
		<p>
			تذكّر أن تضيف عدادًا وانتبه إلى أننا نعد تنازليًا في تمريننا وليس تصاعديًا (لا تستخدم <code>++i</code>!).
		</p>
	</li>
</ul>

<p>
	<strong>ملاحظة:</strong> إن بدأت كتابة الحلقة على الشكل فقد يتوقف المتصفح عن التنفيذ إن لم تضع الشرط النهائي، انتبه إلى ذلك. يمكنك لتفادي اﻷمر كتابة الشيفرة ضمن تعليقات ومن ثم تزيل إشارات التعليق عندما تنتهي من كتابة الشيفرة كاملةً.
</p>

<p>
	إن ارتكبت خطأً تستطيع أن تنقر على الزر "Reset" لتعود إلى الوضع الأساسي، كما يمكنك النقر على الزر "Show solution" لترى الحل.
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="800" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/bGJezpJ?default-tab=result" style="width: 100%;" title="Looping Code5">See the Pen Looping Code5 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<h2 id="-6">
	تطبيق عملي: ملء قائمة المدعوين
</h2>

<p>
	نطلب منك في هذا التمرين أخذ قائمة أسماء من مصفوفة ووضعها ضمن قائمة المدعوين، لكن لا نريد دعوة "Phil" و "Lola" لأسباب خاصة.لهذا نحتاج إلى قائمة للمدعوين وأخرى لغير المدعوين. لهذا نطلب منك تحديدًا:
</p>

<ul>
	<li>
		كتابة حلقة تتنقل بين عناصر المصفوفة <code>people</code>.
	</li>
	<li>
		تتحقق في كل مرور من أن اسم الشخص ليس "Phil"أو "Lola" مستخدمًا عبارة شرطية:
	</li>
	<li>
		إن كان كذلك، ألحق الاسم بنهاية المحتوى النصي <code>textContent</code> للفقرة النصية <code>refused</code> يليه فاصلة وفراغ.
	</li>
	<li>
		إن لم يكن كذلك، ألحق الاسم بنهاية المحتوى النصي <code>textContent</code> للفقرة النصية <code>admitted</code> يليه فاصلة وفراغ.
	</li>
</ul>

<p>
	زوّدناك مسبقًا بأسطر الشيرة التالية:
</p>

<ul>
	<li>
		السطر <code>=+refused.textContent</code> الذي يمثل بداية أمر ضم شيء ما إلى نهاية <code>refused.textContent</code>.
	</li>
	<li>
		السطر <code>=+admitted.textContent</code> الذي يمثل بداية أمر ضم شيء ما إلى نهاية <code>admitted.textContent</code>.
	</li>
</ul>

<p>
	وإليك بطلب آخر يمنحك نقاطًا إضافية: بعد إكمالك المهمتين السابقتين بنجاح سنتركك مع قائمتين من الأسماء تفصل بينها فواصل لكنها غير مرتبة. هل تستطيع اقتطاع الفواصل ووضع نقطة آخر القائمة؟ عد إلى مقال <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D8%A7%D9%84%D9%86%D8%B5%D9%8A%D8%A9-strings-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r817/" rel="">توابع جافا سكريبت للتعامل مع النصوص</a> إن احتجت أي مساعدة.
</p>

<p>
	إن ارتكبت خطأً تستطيع أن تنقر على الزر "Reset" لتعود إلى الوضع الأساسي، كما يمكنك النقر على الزر "Show solution" لترى الحل.
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="900" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/QWPEYGL?default-tab=result" style="width: 100%;" title="Looping Code6">See the Pen Looping Code6 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<h2 id="-7">
	ما هو نوع الحلقة التي علي استخدامها؟
</h2>

<p>
	إن كنت ستتنقل ضمن عناصر مصفوفة أو أي كائن يدعم ذلك ولن تحتاج إلى دليل العنصر (موقعه) في كل مرة، استخدم <code>for...of</code> فهي أسهل قراءة وأقل توليدًا للأخطاء. واستخدم <code>for</code> و <code>while</code> و <code>do...while</code> لبقية الحالات ، فجميعها تخدمك لحل نفس المسائل. أما أيها ستختار فهذا أمر شخصي وذلك وفقًا لسهولة تطبيقها أو وضوحها بالنسبة إليك. لكننا ننصحك باستخدام <code>for</code> كبداية لأن ترتيب وموقع عناصرها أسهل تذكرًا (جميعها ضمن القوسين التاليين للكلمة المحجوزة <code>for</code>) فلن تنسى أيًا منها.
</p>

<p>
	لنلق نظرة عليها جميعًا:
</p>

<ol>
	<li>
		الحلقة <code>for...of</code>:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_64" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> item </span><span class="kwd">of</span><span class="pln"> array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// code to run</span><span class="pln">
</span><span class="pun">}</span></pre>

<ol start="2">
	<li>
		الحلقة<code>for</code>:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_66" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">initializer</span><span class="pun">;</span><span class="pln"> condition</span><span class="pun">;</span><span class="pln"> final</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// code to run</span><span class="pln">
</span><span class="pun">}</span></pre>

<ol start="3">
	<li>
		الحلقة <code>while</code>:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_68" style=""><span class="pln">initializer
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">condition</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// code to run</span><span class="pln">

  final</span><span class="pun">-</span><span class="pln">expression
</span><span class="pun">}</span></pre>

<ol start="4">
	<li>
		الحلقة <code>do...while</code>:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5008_70" style=""><span class="pln">initializer
</span><span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// code to run</span><span class="pln">

  final</span><span class="pun">-</span><span class="pln">expression
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">condition</span><span class="pun">)</span></pre>

<p>
	<strong>ملاحظة</strong>: هناك حلقات أخرى لها ميزات مختلفة وفوائد في حالات محددة وخاصة لكننا لن نمر عليها في هذا المقال.
</p>

<h2 id="-8">
	خلاصة
</h2>

<p>
	قدمنا لك في هذا المقال المفاهيم الأساسية والخيارات المختلفة عند تكرار تنفيذ شيفرة جافا سكريبت عبر الحلقات. وعرضنا أهمية هذا النوع من البنى البرمجية في التعامل مع الحالات التي تتكرر فيها الشيفرة نفسها وأوضحنا طريقة عملها من خلال أمثلة عدة. إن استعصى عليك فهم أية نقطة، عد إليها مجددًا أو اطرح سؤالك عبر نقاش الصفحة.
</p>

<p>
	ترجمة -وبتصرف- لمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code" rel="external nofollow">Looping code</a>
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B9%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%88%D8%A7%D8%AA%D8%AE%D8%A7%D8%B0-%D8%A7%D9%84%D9%82%D8%B1%D8%A7%D8%B1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2271/" rel="">العبارات الشرطية واتخاذ القرار في جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%B5%D9%81%D8%B1-%D8%AD%D8%AA%D9%89-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81-r2046/" rel="">تعلم جافا سكريبت من الصفر حتى الاحتراف</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%87%D9%8A%D9%83%D9%84-%D8%A7%D9%84%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1232/" rel="">هيكل البرنامج في جافاسكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B1%D9%85%D9%8A%D8%B2-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1283/" rel="">ترميز النصوص والتعامل مع كائنات الملفات في جافاسكربت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2277</guid><pubDate>Mon, 18 Mar 2024 09:05:01 +0000</pubDate></item><item><title>&#x62A;&#x62C;&#x631;&#x628;&#x62A;&#x643; &#x627;&#xFEF7;&#x648;&#x644;&#x649; &#x645;&#x639; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D8%AC%D8%B1%D8%A8%D8%AA%D9%83-%D8%A7%EF%BB%B7%D9%88%D9%84%D9%89-%D9%85%D8%B9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2273/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_03/---.png.30f2f85bad3c590f7148d8bc6bbde6b3.png" /></p>
<p>
	بعد أن اطلعنا في <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D8%B1%D9%91%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D9%85%D9%86%D8%B8%D9%88%D8%B1-%D8%B9%D8%A7%D9%85-r2266/" rel="">مقال سابق</a> على مفهوم جافا سكريبت وما يمكنها فعله، سنتابع في مقالنا هذا فكرة إنشاء تطبيق بسيط باستخدام جافا سكربت من خلال جولة إرشادية عملية نبني من خلالها تطبيق "خمّن الرقم Guess the number" خطوةً بخطوة. عليك قبل البدء بقراءة هذا المقال أن تٌلّم بأساسيات العمل على الحاسوب و<a href="https://academy.hsoub.com/programming/html/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-html-r1687/" rel="">أساسيات HTML</a> و <a href="https://academy.hsoub.com/programming/css/%D8%AA%D8%B9%D8%B1%D9%91%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-css-r70/" rel="">CSS</a> وكذلك فهم طبيعة جافا سكريبت.
</p>

<p>
	ولا بد أيضًا من اﻹشارة إلى ما يجب أن تتوقعه بعد قراءة هذا المقال، فلا تتوقع أن تتعلم جافا سكريبت أو حتى أن تفهم كل الشيفرة التي نطلب منك كتابتها، بل كل ما نريده هو إعطاؤك فكرة عن طريقة عمل ميزات جافا سكريبت مع بعضها، وكيف تبدو كتابة شيفرة جافا سكريبت. سنعود في مقالات تالية إلى كل الميزات التي نستعرضها في هذا المقال بتفاصيل أكثر. لذا لا تقلق إن لم تفهم كل شيء مباشرةً.
</p>

<p>
	<strong>ملاحظة</strong>: إن الكثير من ميزات شيفرة <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافا سكريبت</a> هي نفسها تقريبًا في لغات البرمجة اﻷخرى مثل الدوال functions والحلقات loops وغيرها. فقد تبدو صياغة الشيفرة مختلفة لكن المفهوم يبقى ذاته.
</p>

<h2 id="-1">
	فكّر مثل مبرمج
</h2>

<p>
	من أصعب اﻷمور التي تصادفك عند <a href="https://academy.hsoub.com/learn-programming/" rel="">تعلم البرمجة</a> هو طريقة تطبيق قواعد اللغة لحل مشاكل فعلية وليس تعلّم هذه القواعد. فعليك إذًا أن تتعلم كيف تفكّر مثل المبرمجين، ويتضمن ذلك الاطلاع على وصف ما يتطلّبه برنامجك ثم تقدير ميزات الشيفرة التي تستخدمها ﻹنجاز المطلوب وكيف ستربط بين هذه الميزات. يتطلب اﻷمر مزيجًا من العمل الجاد والخبرة بصياغة اللغة والتدريب، إضافة إلى لمسة من الإبداع. وكلًما كتبت شيفرة أكثر ستتمكن منها أكثر.
</p>

<p>
	لن نعدك بالطبع أن تكوّن دماغ مبرمج في خمس دقائق، لكن سنتيح لك فرص عديدة كي تمارس تفكير المبرمج لنلق نظرة إذًا على المثال الذي نبنيه في مقالنا ونراجع الغاية العامة من تقسيمه إلى مهام.
</p>

<h2 id="guessthenumber">
	تطبيق -خمّن الرقم Guess the number-
</h2>

<p>
	نعرض في هذا التطبيق كيفية بناء لعبة بسيطة كما في المثال الحي التالي:
</p>

<p>
	<iframe height="200" loading="lazy" src="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/first-splash/number-guessing-game" style="box-sizing: content-box; border: 1px solid var(--border-primary); max-width: 100%; width: calc((100% - 2rem) - 2px); background: rgb(255, 255, 255); border-radius: var(--elem-radius); padding: 1rem;" width="900"></iframe>
</p>

<p>
	حاول أن تجرّب اللعبة وتعتاد عليها قبل أن نتابع، ثم لنتخيل أن مديرك قد أعطاك الوصف الموجز التالي للعبة كي تبنيها:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		أريد منك إنشاء لعبة تخمين عدد. يجب أن تختار اللعبة عددًا عشوائيًا بين 1 و 100 ثم تطلب من اللاعب أن يخمّن هذا العدد خلال 10 محاولات. تُخبر اللعبة اللاعب بعد كل محاولة إن كان تخمينه صحيحًا أو خاطئًا، وإن كان خاطئًا يجب أن تخبره إن كان تخمينه بعيدًا جدًا أو قريبًا جدًا. على اللعبة أيضًا إبلاغ اللاعب باﻷرقام التي جربها سابقًا. تنتهي اللعبة عندما يصيب اللاعب في تخمينه أو عندما تنتهي المحاولات العشر. عندما تنتهي اللعبة يُعطى اللاعب خيار اللعب مجددًا.
	</p>
</blockquote>

<p>
	بعد الاطلاع على الموجز السابق، لا بد أولًا من تقسيم العملية إلى مهام أصغر قابلة للتنفيذ إستنادًا إلى عقلية المبرمج قدر اﻹمكان:
</p>

<ol>
	<li>
		توليد رقم عشوائي بين 1 و 100.
	</li>
	<li>
		تسجيل رقم المحاولة التي وصلها اللاعب ابتداءً من 1.
	</li>
	<li>
		إعطاء اللاعب طريقة ليسجًل العدد الذي يخمّنه.
	</li>
	<li>
		تسجيل العدد الذي خمّنه اللاعب وعرضه في مكان ما كي يرى محاولاته السابقة.
	</li>
	<li>
		التحقق من صحة التخمين.
	</li>
	<li>
		إن كان التخمين صحيحًا:
		<ol>
			<li>
				عرض رسالة تهنئة.
			</li>
			<li>
				منع اللاعب من إدخال أية تخمينات أخرى (لأن ذلك يسيء إلى اللعبة).
			</li>
			<li>
				عرض آلية تتيح للاعب اللعب مجددًا.
			</li>
		</ol>
	</li>
	<li>
		إن كان التخمين خاطئًا:
		<ol>
			<li>
				إخبار اللاعب أن تخمينه خاطئ وإن كان التخمين قريبًا جدًا أو بعيدًا جدًا.
			</li>
			<li>
				السماح للاعب بإدخال تخمين جديد.
			</li>
			<li>
				زيادة عدّاد المحاولات بمقدار 1.
			</li>
		</ol>
	</li>
	<li>
		إن كان التخمين خاطئًا وتجاوز اللاعب عدد المحاولات المتاحة:
		<ol>
			<li>
				إبلاغ اللاعب بانتهاء اللعبة.
			</li>
			<li>
				منع اللاعب من إدخال أية تخمينات أخرى (لأن ذلك يسيء إلى اللعبة).
			</li>
			<li>
				عرض آلية تتيح للاعب اللعب مجددًا.
			</li>
		</ol>
	</li>
	<li>
		التأكد عند إعادة اللعبة أن منطق اللعبة وواجهة المستخدم قد عادا إلى الوضع اﻷصلي، ثم العودة إلى الخطوة 1.
	</li>
</ol>

<p>
	سنحاول اﻵن التفكير بآلية لتحويل هذه الخطوات إلى شيفرة صحيحة ثم بناء اللعبة واكتشاف ميزات جافا سكريبت أثناء تقدم العمل.
</p>

<h3 id="-2">
	اﻹعدادات اﻷساسية
</h3>

<p>
	لنبدأ العمل على كتابة الشيفرة البرمجية للعبة تخمين الأرقام والتي ستعمل كما موضح في الصورة التالية.
</p>

<p style="text-align: center;">
	<img alt="لعبة تخمين أرقام باستخدام جافا سكريبت.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="146700" data-ratio="49.33" data-unique="djj6waz7k" style="width: 600px; height: auto;" width="746" src="https://academy.hsoub.com/uploads/monthly_2024_03/1229288561_.PNG.314db7e2382a5d498611f7fdf8547509.PNG">
</p>

<p>
	تحتاج في البداية لتحضير نسخة محلية خاصة بك من الملف <a href="https://github.com/mdn/learning-area/blob/main/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html" rel="external nofollow">number-guessing-game-start.html</a> كما تستيطع أن <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html" rel="external nofollow">تختبره مباشرة</a> ضمن المستودع المخصص له على جيت-هب. افتح الملف ضمن المتصفح وضمن المحرر النصي. سترى للوهلة الأولى ترويسة بسيطة وفقرة نصية توضح التعليمات ونموذج لإدخال التخمين، لكن التطبيق لن يعمل حاليًا.
</p>

<p>
	سنضع كل شيفرة اللعبة ضمن العنصر <code>&lt;script&gt;</code> في نهاية شيفرة HTML:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1105_9" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// Your JavaScript goes here</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<h3 id="-3">
	إضافة متغيرات لتخزين البيانات
</h3>

<p>
	أضف بداية الأسطر التالية ضمن العنصر <code>&lt;script&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_11" style=""><span class="kwd">let</span><span class="pln"> randomNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> guesses </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">".guesses"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> lastResult </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">".lastResult"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> lowOrHi </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">".lowOrHi"</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> guessSubmit </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">".guessSubmit"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> guessField </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">".guessField"</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">let</span><span class="pln"> guessCount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> resetButton</span><span class="pun">;</span></pre>

<p>
	يهيئ هذا القسم من الشيفرة المتغيرات والثوابت التي نحتاجها لتخزين البيانات اللازمة لبرنامجنا. تُعرّف <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-r671/" rel="">المتغيرات</a> variables مبدئيًا بأنها أسماء لقيم مثل اﻷعداد أو النصوص. ويمكنك إنشاء متغير باستخدام التعليمة <code>let</code> يليها اسم المتغير. وتُعرّف الثوابت constant بأنها أسماء لقيم أيضًا لكن لا يمكن تغيير هذه القيم بمجرد أن نهيئها. نستخدم في حالتنا الثوابت لتخزين مراجع إلى عناصر من واجهة المستخدم. وقد يتغير النص ضمن تلك العناصر لكن الثوابت تشير دائمًا إلى العنصر نفسه الذي ضُبطت عليه في البداية. يمكن إنشاء الثابت باستخدام التعليمة <code>const</code> يليها اسم الثابت. يمكن إسناد قيمة إلى الثابت أو المتغير باستخدام الإشارة (<code>=</code>) تليها القيمة التي تريد.
</p>

<p>
	في مثالنا:
</p>

<ul>
	<li>
		يُسند إلى المتغير اﻷول <code>randomNumber</code> عدد عشوائي بين 1 و 100 يُحسب من خلال خوارزمية رياضية.
	</li>
	<li>
		أنشئت الثوابت الثلاث اﻷولى لتخزين مراجع إلى المقاطع النصية الخاصة بالنتائج في شيفرة HTML وتستخدم ﻹدراج نصوص ضمن هذه الفقرات برمجيًا، ولاحظ أنها ضمن عنصر <code>&lt;div&gt;</code>والذي يُستخدم لاختيار المقاطع الثلاث لتصفيرها (إعادتها إلى وضعها اﻷصلي) لاحقًا عن إعادة اللعبة إلى وضعها اﻷصلي.
	</li>
</ul>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1105_13" style=""><span class="pln">  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"resultParas"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"guesses"</span><span class="tag">&gt;&lt;/p&gt;</span><span class="pln">
    </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"lastResult"</span><span class="tag">&gt;&lt;/p&gt;</span><span class="pln">
    </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"lowOrHi"</span><span class="tag">&gt;&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span></pre>

<ul>
	<li>
		يُخّزن الثابتان التاليان مرجع إلى عنصر اﻹدخال النصي في النموذج وإلى زر اﻹرسال وتُستخدمان للتحكم بإرسال العدد الذي يُخمنه اللاعب.
	</li>
</ul>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1105_15" style=""><span class="pln">  </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"guessField"</span><span class="tag">&gt;</span><span class="pln">Enter a guess: </span><span class="tag">&lt;/label&gt;</span><span class="pln">
  </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"number"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"guessField"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"guessField"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Submit guess"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"guessSubmit"</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<ul>
	<li>
		يٌخزّن المتغيران اﻷخيران القيمة 1 لعدد محاولات اللعب (ويُستخدم لتتبع عدد المحاولات التي قام بها اللاعب) ومرجعًا إلى زر إعادة الضبط الذي لا يظهر حاليًا (لكنه سيظهر لاحقًا). <strong>ملاحظة</strong>: سنتعلم أكثر عن المتغيرات والثوابت لاحقًا في سلسلة المقالات هذه عن جافا سكريبت.
	</li>
</ul>

<h3 id="-4">
	الدوال
</h3>

<p>
	أضف تاليًا الشيفرة التالية تحت الشيفرة السابقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_17" style=""><span class="kwd">function</span><span class="pln"> checkGuess</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="str">"I am a placeholder"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الدوال هي كتل من الشيفرة يمكن استخدامها مجددًا، إذ يمكن كتابتها مرة واحدة وتنفيذها مرارًا وتكرارًا موفرين عناء كتابة الشيفرة من جديد، وهذا أمر غاية في اﻷهمية.وهنالك عدد من الطرق في تعريف الدوال لكننا سنركز الآن على نوع بسيط. نستخدم في مثالنا الكلمة المفتاحية <code>function</code> متبوعةً باسم الدالة وبعدها قوسين معقوصين<code>{}</code>. نضع الشيفرة التي تنفذها الدالة عند استدعائها داخل القوسين المعقوصين. وعندما نريد تنفيذ الشيفرة، تكتب اسم الدالة يليها قوسين <code>()</code> لنجرب ذلك اﻵن، احفظ التغييرات التي أجريتها على الملف وحدّث الصفحة ضمن المتصفح. انتقل بعد ذلك إلى (<a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwi395Glnq-BAxXZUqQEHfYCD2oQFnoECBQQAQ&amp;url=https%3A%2F%2Facademy.hsoub.com%2Fprogramming%2Fworkflow%2F%25D8%25A3%25D8%25AF%25D9%2588%25D8%25A7%25D8%25AA-%25D9%2585%25D8%25B7%25D9%2588%25D8%25B1%25D9%258A-%25D8%25A7%25D9%2584%25D9%2588%25D9%258A%25D8%25A8-%25D8%25A7%25D9%2584%25D9%2585%25D8%25AF%25D9%2585%25D8%25AC%25D8%25A9-%25D9%2581%25D9%258A-%25D8%25A7%25D9%2584%25D9%2585%25D8%25AA%25D8%25B5%25D9%2581%25D8%25AD%25D8%25A7%25D8%25AA-r1439%2F&amp;usg=AOvVaw3Szq_fVHtH0NCinZTMqjYN&amp;opi=89978449" rel="external nofollow">طرفية جافا سكريبت ضمن أدوات مطوري ويب</a> ثم أدخل السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_19" style=""><span class="pln">checkGuess</span><span class="pun">();</span></pre>

<p>
	من المفترض أن ترى بعد الضغط على المفتاح <code>Enter/Return</code> رسالة تنبيه نصها <code>I am a placeholder</code>، ﻷننا عرفنا دالة في شيفرتنا تعيد هذه الرسالة كلما استدعيناها. <strong>ملاحظة</strong>: سنتعلم أكثر عن الدوال لاحقًا في سلسلة المقالات هذه.
</p>

<h3 id="-5">
	العوامل
</h3>

<p>
	تسمح العوامل <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D8%B9%D8%A7%D9%85%D9%84%D8%A7%D8%AA-%D9%81%D9%8A-javascript-r699/" rel="">Operators</a> في لغة جافا سكريبت بإجراء اختبارات وتنفيذ العمليات الرياضية وضم السلاسل النصية إلى بعضها وغيرها من اﻷشياء. فإن لم تكن قد فعلت ذلك مسبقًا، احفظ التغييرات على ملفك ثم أعد تحميل الصفحة في المتصفح وانتقل إلى طرفية جافا سكريبت في أدوات مطوري ويب. حاول أن تنفذ اﻷمثلة المذكورة في الجدول التالي، منتبهًا إلى نقل المثال حرفيًا كما هو ثم انقر <code>Enter</code> بعد كل عملية لترى نتيجتها:
</p>

<table>
	<thead>
		<tr>
			<th style="text-align:left;">
				العامل
			</th>
			<th style="text-align:left;">
				اسمه
			</th>
			<th style="text-align:left;">
				مثال
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:left;">
				<code>+</code>
			</td>
			<td style="text-align:left;">
				الجمع
			</td>
			<td style="text-align:left;">
				<code>6 + 9</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>-</code>
			</td>
			<td style="text-align:left;">
				الطرح
			</td>
			<td style="text-align:left;">
				<code>20 - 15</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>*</code>
			</td>
			<td style="text-align:left;">
				الضرب
			</td>
			<td style="text-align:left;">
				<code>3 * 7</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>/</code>
			</td>
			<td style="text-align:left;">
				القسمة
			</td>
			<td style="text-align:left;">
				<code>10 / 5</code>
			</td>
		</tr>
	</tbody>
</table>

<p>
	هنالك أيضًا بعض العوامل المختصرة تُدعى عوامل اﻹسناد المركّبة compound assignment operators، فإن أردت مثلًا إضافة عدد جديد إلى عدد موجود وإعادة النتيجة، إليك الطريقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_21" style=""><span class="kwd">let</span><span class="pln"> number1 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
number1 </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span></pre>

<p>
	وهذا مشابه لعمل الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_23" style=""><span class="kwd">let</span><span class="pln"> number2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
number2 </span><span class="pun">=</span><span class="pln"> number2 </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span></pre>

<p>
	وعند تنفيذ اختبارات نتيجتها (صحيح أو خاطئ) وذلك ضمن العبارات الشرطية (سنراها لاحقًا) نستخدم عوامل الموازنة comparison operators مثل:
</p>

<table>
	<thead>
		<tr>
			<th style="text-align:left;">
				العامل
			</th>
			<th style="text-align:left;">
				الاسم
			</th>
			<th style="text-align:left;">
				مثال
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:left;">
				<code>===</code>
			</td>
			<td style="text-align:left;">
				مساواة تامة (هل يساويه تمامًا؟)
			</td>
			<td style="text-align:left;">
				<code>5===2+4 // خاطئ</code>، <code>chris===pop// خاطئ</code>، <code>5===2+3 // صحيح</code>، <code>2==='2' // خاطئ موازنة رقم بنص</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>==!</code>
			</td>
			<td style="text-align:left;">
				لا مساواة تامة (هل هما غير متساويين؟)
			</td>
			<td style="text-align:left;">
				<code>5==!2+4 // صحيح</code>، <code>chris!==pop// صحيح</code>، <code>5==! 2+3 // خاطئ</code>، <code>2==!'2' // صحيح موازنة رقم بنص</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>&lt;</code>
			</td>
			<td style="text-align:left;">
				أقل من
			</td>
			<td style="text-align:left;">
				<code>10&gt;6 // صحيح</code>، <code>10&gt;20 //خاطئ</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>&gt;</code>
			</td>
			<td style="text-align:left;">
				أكبر من
			</td>
			<td style="text-align:left;">
				<code>10&lt;6 // خاطئ</code>، <code>10&lt;20 //صحيح</code>
			</td>
		</tr>
	</tbody>
</table>

<h3 id="-6">
	السلاسل النصية
</h3>

<p>
	تستخدم <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D8%A7%D9%84%D9%86%D8%B5%D9%8A%D8%A9-strings-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r817/" rel="">السلاسل النصية</a> لتمثيل النصوص، وقد رأينا سابقًا متغير نصي في الشيفرة <code>"I am a placeholder"</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_25" style=""><span class="kwd">function</span><span class="pln"> checkGuess</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="str">"I am a placeholder"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن التصريح عن سلسلة نصية باستخدام إشارتي التنصيص المزدوجتين (<code>" "</code>) أو المفردتين (<code>' '</code>)، لكن ينبغي عليك استخدام أحد اﻷسلوبين من بداية السلسلة إلى نهايتها فلا يمكن أن تكتب مثلًا" <code>"I am a placeholder'</code>. باﻹمكان أيضًا تعريف السلسلة النصية بين علامتي اقتباس مائلتين (``) وتُدعى السلاسل المعرّفة بهذا الشكل بالقوالب المفسّرة template literals التي تحمل بعض الخاصيات المميزة وتحديدًا إمكانية وضع متغيرات أخرى أو تعابير برمجية ضمن السلسلة النصية لتتحول قيمها إلى جزء من النص:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_27" style=""><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Mahalia"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> greeting </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Hello</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">name</span><span class="pun">}`;</span></pre>

<p>
	يمنحك هذا اﻷمر أسلوبًا لضم السلاسل النصية معًا.
</p>

<h3 id="-7">
	العبارات الشرطية
</h3>

<p>
	بالعودة إلى الدالة <code>()ckeckGuess</code> نجد أنه من المنطقي ألا تكون وظيفتها طباعة رسالة فقط، بل من المفترض أن تتحقق من صحة العدد الذي يخمّنه اللاعب وتعيد الجواب الملائم. لنستبدل اﻵن بالشيفرة التالية ما كان موجودًا ضمن الدالة <code>()ckeckGuess</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_29" style=""><span class="kwd">function</span><span class="pln"> checkGuess</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> userGuess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">guessField</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">guessCount </span><span class="pun">===</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    guesses</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Previous guesses:"</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  guesses</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">guesses</span><span class="pun">.</span><span class="pln">textContent</span><span class="pun">}</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">userGuess</span><span class="pun">}`;</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">userGuess </span><span class="pun">===</span><span class="pln"> randomNumber</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    lastResult</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Congratulations! You got it right!"</span><span class="pun">;</span><span class="pln">
    lastResult</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">backgroundColor </span><span class="pun">=</span><span class="pln"> </span><span class="str">"green"</span><span class="pun">;</span><span class="pln">
    lowOrHi</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
    setGameOver</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">guessCount </span><span class="pun">===</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    lastResult</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"!!!GAME OVER!!!"</span><span class="pun">;</span><span class="pln">
    lowOrHi</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
    setGameOver</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    lastResult</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Wrong!"</span><span class="pun">;</span><span class="pln">
    lastResult</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">backgroundColor </span><span class="pun">=</span><span class="pln"> </span><span class="str">"red"</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">userGuess </span><span class="pun">&lt;</span><span class="pln"> randomNumber</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      lowOrHi</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Last guess was too low!"</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">userGuess </span><span class="pun">&gt;</span><span class="pln"> randomNumber</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      lowOrHi</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Last guess was too high!"</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  guessCount</span><span class="pun">++;</span><span class="pln">
  guessField</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  guessField</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ما وضعناه كمية كبيرة من الشيفرة بالفعل، لكن سنمر على كل قسم منها ونشرحه:
</p>

<ul>
	<li>
		يعرّف السطر اﻷول متغيرًا يُدعى <code>userGuess</code> وتُسند إليه القيمة التي أُدخلت ضمن المربع النصي في النموذج. نمرر بعد ذلك هذه القيمة إلى الدالة <code>()Number</code> المدمجة في جافا سكريبت وذلك للتأكد أن هذه القيمة عدد بالفعل. وطالما أننا لن نغيّر هذا العدد فقد قررنا أن يكون ثابتًا <code>const</code>.
	</li>
	<li>
		نواجه بعد ذلك أول كتلة شرطية، وتُستخدم الكتل الشرطية لتنفيذ الشيفرة انتقائيًا إن تحقق شرط معين أو لم يتحقق. قد تبدو العبارة الشرطية شبيهة بالدالة لكنه ليست كذلك. تبدأ أبسط أشكال الكتل الشرطية بالكلمة المحجوزة <code>if</code> يليها بعض اﻷقواس ثم بعض اﻷقواس المعقوصة. يوضع الشرط أو الاختبار بين اﻷقواس العادية، فإن أعاد تنفيذ الشرط النتيجة <code>true</code> تُنفَّذ الشيفرة الموجودة ضمن اﻷقواس المعقوصة، وإن لم يكن اﻷمر كذلك، فلن تنفَّذ تلك الشيفرة وينتقل التنفيذ إلى القسم اﻵخر من الشيفرة. يختبر الشرط فيما لو كانت قيمة المتغيّر <code>guessCount</code> مساويًا للقيمة <code>1</code> (أي إذا كانت هذه المحاولة اﻷولى للاعب أم لا):
	</li>
</ul>

<pre class="ipsCode">  guessCount === 1;
</pre>

<p>
	إن تحقق ذلك، نجعل النص المحتوى ضمن الفقرة النصية <code>guesses</code> مساويًا <code>Previous guesses</code>، وإن لم يتحقق لا نفعل ذلك.
</p>

<ul>
	<li>
		نستخدم بعد ذلك قالبًا مفسّرًا لضم قيمة المتغّير <code>userGuess</code> إلى نهاية النص في الفقرة النصية <code>guesses</code> مع وجود مسافة فارغة بينهما.
	</li>
	<li>
		تُنفِّذ الشيفرة التالية عدة اختبارات:
	</li>
	<li>
		تتحق العبارة الشرطية اﻷولى <code>{}()if</code> إن كان التخمين الذي أدخله اللاعب مساويًا قيمة المتغيّر <code>randomNumber</code> الذي ضُبطت قيمته في بداية الشيفرة. فإن كان تخمين اللاعب صحيحًا، ربح اللعبة، لهذا نعرض رسالة تهنئة بلون أخضر ونمسح محتويات صندوق المعلومات الذي يشير إلى بعد أوقرب التخمين الخاطئ عن القيمة الصحيحة، ثم تُنفَّذ الدالة <code>()setGameOver</code> التي سنناقشها لاحقًا.
	</li>
	<li>
		نربط بعد ذلك اختبارًا آخر في نهاية اﻷول من خلال البنية <code>{}()else if</code> والتي تتحقق إن كان الدور الذي لعبه اللاعب هو آخر دور له. فإن كان كذلك، يكرر ما فعلناه في الكتلة السابقة لكن مع رسالة تشير إلى نهاية اللعبة بدلًا من رسالة التهنئة.
	</li>
	<li>
		أما الكتلة اﻷخيرة التي نربطها بسابقتها فهي الكتلة <code>{}else</code> التي تضم شيفرة تُنفَّذ فقط إن فشل الاختباران في الكتلتين السابقتين (أي اللاعب لم يخمن العدد، ,ولم ينهي جميع محاولاته). نخبره في هذه الحالة أن تخمينه خاطئ ثم ننفذ اختبارًا آخر يتحقق إن كان تخمينه أكبر بكثير أو أقل بكثير من العدد الصحيح ثم نعرض رسالة أخرى بطريقة مناسبة ﻹخبار اللاعب بذلك.
	</li>
	<li>
		تحضر اﻷسطر الثلاث اﻷخيرة من الدالة (من 26 إلى 28) إرسال لتخمين التالي. إذ تضيف <code>1</code> إلى المتغير <code>guessCount</code> كي يستنفذ اللاعب دورًا جديدًا<br>
		(العامل <code>++</code> هو عامل يزيد قيمة المتغير بمقدار 1). وتفرّغ قيمة المربع النصي في النموذج وتعطيه تركيز الدخل مجددًا، وبهذا يصبح اللاعب جاهزًا ﻹدخال التخمين التالي.
	</li>
</ul>

<h3 id="-8">
	اﻷحداث
</h3>

<p>
	ما فعلنا حتى اﻵن هو إنجاز الدالة لكنها لن تفعل شيئًا لأننا لم نستدعها بعد. ومن المنطقي أن نستدعي هذه الدالة عند النقر على زر "Submit guess"، ولإنجاز ذلك، نحتاج إلى ما يُدعى <strong>حدثًا event</strong>. <a href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%87%D9%85-%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r690/" rel="">فاﻷحداث</a> هي أشياء تحدث في المتصفح مثل نقر زر أو تحميل صفحة أو تشغيل فيديو وغيرها. ولكي ينفّذ المتصفح كتلة من الشيفرة كاستجابة لحدث ما نحتاج إلى <strong>مترصّد أحداث event listener</strong> يراقب أحداث معينة ويستدعي <strong>معالج أحداث event handler</strong> مناسب، والمعالج هو كتل من الشيفرة تعمل استجابةً لوقوع حدث في المتصفح. أضف السطر التالي تحت الدالة <code>()checkGuess</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_31" style=""><span class="pln">guessSubmit</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> checkGuess</span><span class="pun">);</span></pre>

<p>
	أضفنا هنا مترصّد أحداث إلى الزر، وهو تابع يأخذ قيمتين (تُدعيان وسيطين arguments)، اﻷول هو نوع الحدث الذي نترصده فهو حدث (النقر <code>click</code>) وله قيمة نصية، والثاني هو الشيفرة التي تُنفَّذ عند وقوع الحدث وهي في حالتنا الدالة <code>()checkGuess</code>. ولاحظ أنه لا حاجة لوضع القوسين عند كتابة الدالة كوسيط لمترصد الحدث <code>()addEventListener</code> جرّب حفظ التغييرات على الملف ثم إعادة تحميل الصفحة في متصفحك وسيعمل التطبيق إلى حد معين. وما سيحدث أنه لو خمّنت العدد الصحيح أو أنهيت كل محاولاتك ستنهار اللعبة لأننا لم نعرّف بعد الدالة <code>()setGameOver</code> التي من المفترض أن تُستدعى عند نهاية اللعبة. لهذا سنضيف الشيفرة الناقصة ﻹكمال اللعبة
</p>

<h3 id="-9">
	إنهاء جميع وظائف اللعبة
</h3>

<p>
	لنضف اﻵن الدالة <code>()setGameOver</code> إلى أسفل الشيفرة التي كتبتها حتى اﻵن ثم نشرح ما تفعله:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_33" style=""><span class="kwd">function</span><span class="pln"> setGameOver</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  guessField</span><span class="pun">.</span><span class="pln">disabled </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
  guessSubmit</span><span class="pun">.</span><span class="pln">disabled </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
  resetButton </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"button"</span><span class="pun">);</span><span class="pln">
  resetButton</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Start new game"</span><span class="pun">;</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">resetButton</span><span class="pun">);</span><span class="pln">
  resetButton</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> resetGame</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
	<li>
		يعطّل أول سطرين عمل عنصر اﻹدخال النصي في النموذج وعمل الزر بضبط الخاصية <code>disabled</code> على القيمة <code>true</code>لكل منهما. وهذا اﻷمر ضروري، لأن اللاعب سيتمكن من إرسال قيم تخمين أخرى رغم إنتهاء اللعبة، وسيجعل ذلك اللعبة فوضوية.
	</li>
	<li>
		توّلد اﻷسطر الثلاث التالية زرًا جديدًا <code>&lt;button&gt;</code>بعنوان "Start new game" ومن ثم تضيفه إلى شيفرة HTML الموجودة.
	</li>
	<li>
		يضبط السطر اﻷخير مترصّد أحداث للزر الجديد كي يترصد حدث النقر عليه ويستدعي الدالة <code>()resetGame</code>. علينا اﻵن كتابة الشيفرة الخاصة بالدالة اﻷخيرة، لهذا ضع الشيفرة التالية في آخر ما كتبته:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_35" style=""><span class="kwd">function</span><span class="pln"> resetGame</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  guessCount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> resetParas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">".resultParas p"</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> resetPara </span><span class="kwd">of</span><span class="pln"> resetParas</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    resetPara</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  resetButton</span><span class="pun">.</span><span class="pln">parentNode</span><span class="pun">.</span><span class="pln">removeChild</span><span class="pun">(</span><span class="pln">resetButton</span><span class="pun">);</span><span class="pln">

  guessField</span><span class="pun">.</span><span class="pln">disabled </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
  guessSubmit</span><span class="pun">.</span><span class="pln">disabled </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
  guessField</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  guessField</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">

  lastResult</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">backgroundColor </span><span class="pun">=</span><span class="pln"> </span><span class="str">"white"</span><span class="pun">;</span><span class="pln">

  randomNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هذه الكتلة من الشيفرة طويلة نوعًا ما وتعيد كل شيء إلى وضعه اﻷصلي عند بداية اللعبة، وبالتالي يصبح اللاعب قادرًا على المتابعة من جديد، فهي:
</p>

<ul>
	<li>
		تعيد قيمة المتغير <code>guessCount</code> إلى 1.
	</li>
	<li>
		تفرّغ كل ما هو موجود في الفقرات النصية. فقد اخترنا جميع الفقرات النصية ضمن العنصر <code>&lt;div class="resultParas"&gt;&lt;/div&gt;</code> ثم تفقدنا من خلال حلقة كل فقرة وضبطنا الخاصية <code>textContent</code> لكل منها على<code>' '</code> (سلسلة فارغة).
	</li>
	<li>
		تزيل زر إعادة الضبط من الشيفرة.
	</li>
	<li>
		تفعّل عناصر النموذج وتفرّغ الفقرات النصية وتعطي تركيز الدخل إلى مربع اﻹدخال النصي في النموذج كي يصبح جاهزًا لتلقي تخمين جديد من قبل اللاعب.
	</li>
	<li>
		تزيل لون خلفية الفقرة النصية <code>lastResult</code>.
	</li>
	<li>
		توّلد رقم عشوائي جديد كي لا تخمّن نفس الرقم العشوائي السابق. <strong>لقد اكتملت اللعبة اﻵن، تهانينا!</strong> وكل ما بقي لنا في هذا المقال هو الحديث عن بعض الميزات الهامة التي رأيناها في شيفرة اللعبة والتي ربما لم تدركها.
	</li>
</ul>

<h3 id="-10">
	الحلقات
</h3>

<p>
	من أهم أجزاء الشيفرة التي كتبناها، والتي لا بد من الحديث عنها هي <a href="https://academy.hsoub.com/programming/java/%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A9-%D8%AD%D9%84%D9%82%D8%A9-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-for-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1065/" rel="">حلقة (for…of)</a>. فالحلقات هي مفاهيم برمجية غاية في اﻷهمية تتيح لك تنفيذ جزء من الشيفرة مرارًا وتكرارًا حتى يتحقق شرط معين. وكي نبدأ تتبع عمل الحلقات انتقل إلى طرفية جافا سكريبت في أدوات مطوري ويب، ثم أدخل الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_37" style=""><span class="kwd">const</span><span class="pln"> fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"apples"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"bananas"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cherries"</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> fruit </span><span class="kwd">of</span><span class="pln"> fruits</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">fruit</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ما الذي حدث؟ لقد طبعت الكلمات <code>'apples', 'bananas', 'cherries'</code> على الشاشة كنتيجة لتنفيذ الحلقة. لاحظ السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8536_9" style=""><span class="pln"> </span><span class="pun">;[</span><span class="str">'const fruits = ['</span><span class="pln">apples</span><span class="str">', '</span><span class="pln">bananas</span><span class="str">', '</span><span class="pln">cherries </span></pre>

<p>
	يُنشئ هذا السطر مصفوفة (سنتعرف عليها لاحقًا في <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2308/" rel="">مقال لاحق</a>) وهي مبدئيًا مجموعة من العناصر (سلاسل نصية في حالتنا). وتزوّدك الحلقة <code>for...of</code> بطريقة للحصول على كل عنصر من المصفوفة وتطبيق شيفرة جافا سكريبت عليه، فما يفعله<br>
	السطر <code>(for (const fruit of fruits</code> هو التالي:
</p>

<ol>
	<li>
		الحصول على أول عناصر المصفوفة <code>fruits</code>.
	</li>
	<li>
		ضبط قيمة المتغيّر <code>fruit</code> لتكون قيمة العنصر اﻷول، ثم تنفيذ شيفرة جافا سكريبت الموجودة داخل القوسين <code>{}</code>.
	</li>
	<li>
		الحصول على العنصر التالي من المصفوفة <code>fruits</code>.
	</li>
</ol>

<p>
	في هذه الحالة، تطبع الشيفرة قيمة المتغيّر <code>fruit</code> على الشاشة. لنلق نظرة اﻵن على الحلقة الموجودة في لعبة "خمّن الرقم" وتحديدًا ضمن الدالة <code>()resetGame</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_39" style=""><span class="kwd">const</span><span class="pln"> resetParas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">".resultParas p"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> resetPara </span><span class="kwd">of</span><span class="pln"> resetParas</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  resetPara</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	توّلد هذه الشيفرة متغيّرًا يضم قائمة بجميع الفقرات النصية الموجودة ضمن العنصر <code>&lt;div class="resultParas"&gt;</code> باستخدام التابع <code>()querySelectorAll</code> ومن ثم يتفقد كل فقرة باستخدام حلقة ويزيل المحتوى النصي لها. وتجدر الملاحظة أن ثوابت مثل <code>resetParas</code> يمكن إزالة المحتوى النصي لها.
</p>

<h3 id="object">
	مناقشة سريع لمفهوم الكائن Object في جافا سكريبت
</h3>

<p>
	سنضيف تحسينًا أخيرًا إلى اللعبة قبل الدخول في هذا النقاش وهو سطر يجب وضعه تحت السطر <code>;let resetButton</code> بالقرب من بداية شيفرة جافا سكريبت ثم نحفظ التغيرات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_41" style=""><span class="pln">guessField</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span></pre>

<p>
	يستخدم هذا السطر التابع <code>()focus</code> الذي يجعل مؤشر الدخل ضمن عنصر اﻹدخال النصي <code>&lt;input&gt;</code> حالما تُحمّّل الصفحة، وهكذا يصبح اللاعب جاهزًا لكتابة تخمينه مباشرة دون الحاجة إلى النقر داخل مربع اﻹدخال النصي. صحيح أنها إضافة صغيرة لكنها تحسن استخدام اللعبة وتمنح اللاعب فكرة عما سيفعله تاليًا حتى يبدأ اللعب.
</p>

<p>
	لنحلل ما يجري هنا بمزيد من التفصيل. إذ نتعامل غالبًا في جافا سكريبت مع <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-objects-%D9%88%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D9%86%D8%B3%D8%AE-instance-methods-%D9%88%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%86%D8%B3%D8%AE-instance-variables-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1108/" rel="">الكائنات objects</a>، والكائن هو مجموعة مترابطة من الوظائف المخزّنة في شيء واحد. بإمكانك بالطبع إنشاء كائنات خاصة بك، لكن اﻷمر متقدم قليلًا ولن نغطيه في مقالنا. أما ما نناقشه اﻵن باختصار فهي الكائنات المدمجة مع اللغة والتي يتضمنها متصفحك وتسمح لك بتنفيذ العديد من الأمور المفيدة. في هذه الحالة الخاصة، أنشأنا ثابتًا يخزّن مرجعًا إلى عنصر اﻹدخال النصي الموجود في نموذج HTML، وستجد السطر التالي ضمن التصريحات في بداية الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_43" style=""><span class="kwd">const</span><span class="pln"> guessField </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">".guessField"</span><span class="pun">);</span></pre>

<p>
	وللحصول على هذا المرجع، استخدمنا التابع <code>()querySelector</code> العائد إلى الكائن <code>document</code>. ويأخذ هذا التابع معلومة واحدة وهي <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwi4tfncm7SBAxXwRqQEHRUpBGUQFnoECAkQAQ&amp;url=https%3A%2F%2Facademy.hsoub.com%2Fprogramming%2Fcss%2F%25D8%25A7%25D9%2584%25D9%2585%25D8%25AD%25D8%25AF%25D8%25AF%25D8%25A7%25D8%25AA-selectors-%25D9%2581%25D9%258A-css-r249%2F&amp;usg=AOvVaw1j5JwLZaaecZkNHFzLdETL&amp;opi=89978449" rel="external nofollow">محدد CSS</a> الذي يُستخدم ﻹنتقاء العنصر الذي تريد إنشاء مرجع إليه.
</p>

<p>
	ولأن الثابت <code>guessField</code> يحتوي مرجعًا إلى العنصر <code>&lt;input&gt;</code>، فلديه القدرة اﻵن على الوصول إلى خصائصه (تُخزَّن المتغيرات أساسًا ضمن كائنات، ولا يمكن تغيير قيم بعضها) وتوابعه (وهي أساسًا دوال مخزّنة ضمنه). ومن أحد توابع عنصر اﻹدخال النصي نجد <code>()focus</code> لهذا يمكننا استخدام السطر التالي لنقل تركيز الدخل إلى هذا العنصر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_45" style=""><span class="pln">guessField</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span></pre>

<p>
	لا يمكن استخدام التابع <code>()focus</code> على المتغيرات التي لا تضم مراجعًا إلى عناصر، فالثابت <code>guesses</code> مثلًا يضم مرجعًا إلى العنصر <code>&lt;p&gt;</code> والمتغير <code>guessCount</code> يضم عددًا.
</p>

<h3 id="-11">
	التعامل مع كائنات المتصفح
</h3>

<p>
	لنعمل قليلًا مع بعض كائنات المتصفح:
</p>

<ol>
	<li>
		افتح ملف اللعبة أولًا ضمن المتصفح.
	</li>
	<li>
		افتح أدوات مطوري ويب في متصفحك (من زر القائمة&gt;أدوات إضافية&gt;أدوات مطوري ويب "في متصفح فايرفكس"). وتأكد من وصولك إلى طرفية جافا سكريبت.
	</li>
	<li>
		اكتب في الطرفية <code>guessField</code> وستعرض لك حينها أن هذا المتغيّر يضم العنصر <code>&lt;input&gt;</code>، وستلاحظ أيضًا أن الطرفية تعرض لك تلقائيًا أسماء جميع الكائنات الموجودة ضمن بيئة التنفيذ بما في ذلك متغيّراتك التي صرحت عنها.
	</li>
	<li>
		اكتب اﻵن مايلي:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_47" style=""><span class="pln">   guessField</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span></pre>

<p>
	تمثل الخاصية <code>value</code> القيمة الحالية المُدخلة إلى مربع النص، وسترى أن تنفيذ اﻷمر السابق يغيّر النص الموجود في مربع النص.
</p>

<ol start="5">
	<li>
		<p>
			جرّب أن تكتب <code>guesses</code> في الطرفية ثم اضغط المفتاح "Enter" وسترى أن هذا المتغير يتضمن العنصر <code>&lt;p&gt;</code>.
		</p>
	</li>
	<li>
		<p>
			جرّب كتابة اﻷمر التالي: <code>guesses.value</code> وسيعيد المتصفح القيمة <code>undefined</code> لأن الفقرة النصية لا تمتلك الخاصية <code>value</code>
		</p>
	</li>
	<li>
		<p>
			لتغيير النص داخل الفقرة النصية جرّب الأمر التالي: <code>"?guesses.textContent="Where is my paragraph</code>
		</p>
	</li>
	<li>
		<p>
			ولكي تجرب أشياء أخرى، اكتب اﻷسطر التالية:
		</p>
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1105_49" style=""><span class="pln">   guesses</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">backgroundColor </span><span class="pun">=</span><span class="pln"> </span><span class="str">"yellow"</span><span class="pun">;</span><span class="pln">
   guesses</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">fontSize </span><span class="pun">=</span><span class="pln"> </span><span class="str">"200%"</span><span class="pun">;</span><span class="pln">
   guesses</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">padding </span><span class="pun">=</span><span class="pln"> </span><span class="str">"10px"</span><span class="pun">;</span><span class="pln">
   guesses</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">boxShadow </span><span class="pun">=</span><span class="pln"> </span><span class="str">"3px 3px 6px black"</span><span class="pun">;</span></pre>

<p>
	لكل عنصر في الصفحة خاصية تُدعى <code>style</code> تضم بحد ذاتها كائنًا له خاصيات تتضمن جميع تنسيقات CSS السطرية المطبقة على العنصر. ويسمح لنا ذلك ضبط تنسيقات جديدة للعنصر ديناميكيًا من خلال جافا سكريبت.
</p>

<h2 id="-12">
	الخلاصة
</h2>

<p>
	هكذا نكون قد بنينا تطبيقًا بسيط باستخدام جافا سكريبت، استمتع بتجريب ما فعلته أو جرّب <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/first-splash/number-guessing-game.html" rel="external nofollow">النسخة الجاهزة</a> من اللعبة على جيت-هاب كما يمكنك تحميل <a href="https://github.com/mdn/learning-area/blob/main/javascript/introduction-to-js-1/first-splash/number-guessing-game.html" rel="external nofollow">شيفرتها المصدرية</a> أيضًا.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/A_first_splash" rel="external nofollow">Afirst splash into JavaScript</a>
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D8%B1%D9%91%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D9%85%D9%86%D8%B8%D9%88%D8%B1-%D8%B9%D8%A7%D9%85-r2266/" rel="">تعرّف على لغة جافا سكريبت من منظور عام</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%B5%D9%81%D8%B1-%D8%AD%D8%AA%D9%89-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81-r2046/" rel="">تعلم لغة جافا سكريبت من الصفر حتى الاحتراف</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1689/" rel="">أساسيات لغة جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B9%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%88%D8%A7%D8%AA%D8%AE%D8%A7%D8%B0-%D8%A7%D9%84%D9%82%D8%B1%D8%A7%D8%B1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2271/" rel="">العبارات الشرطية واتخاذ القرار في جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-object-oriented-javascript-r179/" rel="">مدخل إلى جافاسكريبت كائنية التوجه (Object-Oriented JavaScript)</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2273</guid><pubDate>Thu, 14 Mar 2024 12:06:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x639;&#x628;&#x627;&#x631;&#x627;&#x62A; &#x627;&#x644;&#x634;&#x631;&#x637;&#x64A;&#x629; &#x648;&#x627;&#x62A;&#x62E;&#x627;&#x630; &#x627;&#x644;&#x642;&#x631;&#x627;&#x631; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B9%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%88%D8%A7%D8%AA%D8%AE%D8%A7%D8%B0-%D8%A7%D9%84%D9%82%D8%B1%D8%A7%D8%B1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2271/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_03/425251064_.png.17619cbafcbc0f8d269eb88519769bb1.png" /></p>
<p>
	نتابع في سلسلة المقالات هذه تغطية أساسيات جافاسكريبت وميزاتها، وتحديدًا أنواع البنى البرمجية التي نصادفها بكثرة في الشيفرة مثل العبارات الشرطية والحلقات والدوال والأحداث. وقد اطلعنا على هذه النقاط بشكل مبسط في سلسلة المقالات السابقة لكننا سنناقشها هنا بشيء من التفصيل.
</p>

<p>
	ننصحك قبل أن تبدأ العمل معنا في هذه السلسلة أن تطلع على:
</p>

<ol>
	<li>
		أساسيات علوم الحاسب.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/html/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-html-r1687/" rel="">أساسيات HTML</a>.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/css/%D8%AA%D8%B9%D8%B1%D9%91%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-css-r70/" rel="">أساسيات عمل CSS</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D8%B1%D9%91%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D9%85%D9%86%D8%B8%D9%88%D8%B1-%D8%B9%D8%A7%D9%85-r2266/" rel="">أساسيات جافاسكربت</a> كما شرحناها في سلسلة المقالات السابقة.
	</li>
</ol>

<p>
	<strong>ملاحظة</strong>: إن كنت تستخدم حاسوب أو جهاز لوحي أو غيره من الأجهزة التي لا تمكّنك من إنشاء ملفاتك الخاصة، جرِّب الشيفرة التي ستجدها في الأمثلة من خلال برامج كتابة شيفرة على الإنترنت مثل Glitch أو JSBin.
</p>

<p>
	نتحدث في هذا المقال عن مفهوم العبارات الشرطية في جافاسكريبت إذ لا بد من اتخاذ قرارات عند كتابة الشيفرة في أية لغة برمجة ومن ثم تنفيذ بعض اﻹجراءات وفقًا لمعطيات الدخل المختلفة. فلو أخذنا لعبة ما كمثال، سنجد أن اللعبة تنتهي عندما يصبح عدد المحاولات المسموحة 0، ونأخذ كمثال آخر تطبيقًا للطقس يعرض صورة شروق الشمس في الصباح ويعرض صورة قمر ونجوم في ساعات الليل. هذا اﻷفعال تقرر من خلال استخدام البنى الشرطية وستكون موضوع هذا المقال.
</p>

<h2 id="-1">
	لماذا نستخدم عبارات شرطية في جافا سكريبت؟
</h2>

<p>
	يتخذ البشر (وكائنات حية أخرى) باستمرار قرارات تؤثر على حياتهم منها البسيطة (كان تقرر تناول قطعة أو قطعتي بسكويت) أو قرارات مصيرية (هل سأبقى في بلدي والعمل في مزرعة أبي أو أن أسافر لأكمل دراستي). وهذا ما تمثله العبارات الشرطية في جافا سكريبت تمامًا، سواء لاتخاذ قرار (أكل قطعة بسكويت واحدة مثلًا) أو معالجة نتائج هذه القرارات (إن اكل قطعة واحد فقد لا أشعر بالشبع، وإن أكلت أكثر فقد أشعر بالتخمة).
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="146306" href="https://academy.hsoub.com/uploads/monthly_2024_03/01_decision_making.png.9dcb5c89bc9564b4775e8c024acf3025.png" rel=""><img alt="01 decision making" class="ipsImage ipsImage_thumbnailed" data-fileid="146306" data-unique="fc0wlice5" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2024_03/01_decision_making.thumb.png.7f8537f8126e8d61f713f6db676a7f91.png"> </a>
</p>

<h2 id="ifelse">
	العبارة الشرطية <code>if...else</code>
</h2>

<p>
	نلقي نظرة في هذا القسم على العبارة الشرطية <code>if...else</code>، وهي أكثر العبارات الشرطية شيوعًا في جافا سكريبت.
</p>

<h3 id="ifelse-1">
	الصياغة القواعدية اﻷساسية للعبارة <code>if...else</code>
</h3>

<p>
	تبدو هذه العبارة بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_8" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">condition</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">/* code to run if condition is true */</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">/* run some other code instead */</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لدينا هنا:
</p>

<ol>
	<li>
		الكلمة المحجوزة <code>if</code> ويليها قوسان عاديان<code>()</code>.
	</li>
	<li>
		شرط يجري اختباره يوضع ضمن القوسين ( مثل هل قيمة ما أكبر من قيمة أخرى أو هل لهذه القيمة وجود؟). وتستخدم الشرط في صياغته عادة <span ipsnoautolink="true">عوامل مقارنة </span>تعيد إحدى النتيجتين صحيح <code>true</code> أو خاطئ <code>false</code>.
	</li>
	<li>
		مجموعة من اﻷقواس المعقوصة {} وضمنها بعض الشيفرة، وقد تكون هذه الشيفرة أي شيء نريده وتُنفَّذ إن تحقق الشرط.
	</li>
	<li>
		الكلمة المحجوزة <code>else</code>.
	</li>
	<li>
		مجموعة أخرى من اﻷقواس المعقوصة، وضمنها بعض الشيفرة التي تُنفَّذ فقط إن لم يتحقق الشرط (كانت نتيجته <code>false</code>).
	</li>
</ol>

<p>
	يمكن بسهولة قراءة الشيفرة السابقة التي تقول "إذا أعاد الشرط النتيجة <code>true</code> نفّذ الشيفرة A وإلا نفّذ الشيفرة B. وتجدر الملاحظة أنه ليس من الضروري تضمين القسم <code>else</code>، فالشيفرة التالية صحيحة تمامًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_10" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">condition</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">/* code to run if condition is true */</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">/* run some other code */</span></pre>

<p>
	لكن لا بد من الانتباه في هذه الحالة إلى أن العبارة الشرطية في هذه الحالة لن تتحكم بكتلة الشيفرة التي تليها والتي ستُنفَّذ أيًا كانت نتيجة الشرط. ولا نعني بذلك أن هذا أمر سيء لكن قد لا يتحقق ما تريده بالطريقة المتوقعة، لأنك غالبًا ما تريد تنفيذ أحد كتلتين من الشيفرة في الحالات الشرطية وليس كلاهما. وأخيرًا قد تجد العبارة الشرطية دون أقواس معقوصة مع أنه أمر غير مرغوب إطلاقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_12" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">condition</span><span class="pun">)</span><span class="pln"> </span><span class="com">/* code to run if condition is true */</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="com">/* run some other code instead */</span></pre>

<p>
	لا يوجد بالطبع خطأ في الصياغة السابقة لكن وجود اﻷقواس يجعل الشيفرة أكثر وضوحًا، فهي توضح حدود الشيفرة التي تتحكم بها العبارة الشرطية، كما أن استخدام أسطر متعددة مع إزاحة مناسبة يسهّل قراءة الشيفرة أكثر.
</p>

<h3 id="-2">
	مثال واقعي
</h3>

<p>
	لفهم صياغة العبارة الشرطية بصورة أفضل، لنتخيل في هذا المثال الواقعي طفلًا يطلب مساعدة أمه أو أبيه في مهمة ما. فقد يقول الوالد أو الوالدة "إن ساعدتني في التسوق سأعطيك مصروفًا إضافيًا كي تشتري اللعبة التي تريد". يمكن أن نمثل اﻷمر في جافا سكريبت كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_14" style=""><span class="kwd">let</span><span class="pln"> shoppingDone </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> childsAllowance</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">shoppingDone </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  childsAllowance </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  childsAllowance </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تجعل الشيفرة السابقة قيمة المتغير <code>shoppingDone</code> دائمًا <code>false</code> وهذا يعني أن ظن الطفل سيخيب. لكن بالطبع يمكننا اقتراح آلية على الوالدين لتصبح قيمة المتغير <code>shoppingDone</code> هي <code>true</code> إن ساعد الطفل الوالد في التسوق.
</p>

<h3 id="elseif">
	التعليمة <code>else if</code>
</h3>

<p>
	يزودنا المثال السابق بخيارين أو نتيجتين، لكن ماذا لو أردنا خيارات أكثر؟ توجد طريقة لربط عدة خيارات أو نتائج إلى العبارة <code>if...else</code> باستخدام التعليمة<br>
	<code>else if</code> التي تضم كتلة إضافية من الشيفرة بين الكتلتين <code>{}()if</code> و <code>{} else</code>.
</p>

<p>
	لنلق نظرة على المثال التالي الذي يصلح أن يكون جزءًا من تطبيق للأحوال الجوية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5790_20" style=""><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"weather"</span><span class="tag">&gt;</span><span class="pln">Select the weather type today: </span><span class="tag">&lt;/label&gt;</span><span class="pln">
</span><span class="tag">&lt;select</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"weather"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">""</span><span class="tag">&gt;</span><span class="pln">--Make a choice--</span><span class="tag">&lt;/option&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"sunny"</span><span class="tag">&gt;</span><span class="pln">Sunny</span><span class="tag">&lt;/option&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"rainy"</span><span class="tag">&gt;</span><span class="pln">Rainy</span><span class="tag">&lt;/option&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"snowing"</span><span class="tag">&gt;</span><span class="pln">Snowing</span><span class="tag">&lt;/option&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"overcast"</span><span class="tag">&gt;</span><span class="pln">Overcast</span><span class="tag">&lt;/option&gt;</span><span class="pln">
</span><span class="tag">&lt;/select&gt;</span><span class="pln">

</span><span class="tag">&lt;p&gt;&lt;/p&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_22" style=""><span class="kwd">const</span><span class="pln"> select </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"select"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> para </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">

select</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"change"</span><span class="pun">,</span><span class="pln"> setWeather</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> setWeather</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> choice </span><span class="pun">=</span><span class="pln"> select</span><span class="pun">.</span><span class="pln">value</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"sunny"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln">
      </span><span class="str">"It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream."</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"rainy"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln">
      </span><span class="str">"Rain is falling outside; take a rain coat and an umbrella, and don't stay out for too long."</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"snowing"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln">
      </span><span class="str">"The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman."</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"overcast"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln">
      </span><span class="str">"It isn't raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case."</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="300" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/jORWRGg?default-tab=result" style="width: 100%;" title="js-making decisions1">See the Pen js-making decisions1 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<ol>
	<li>
		لدينا في الشيفرة السابقة العنصر <code>&lt;select&gt;</code> الذي يسمح لنا باختيار أحد التوقعات الجوية إضافة إلى فقرة نصية بسيطة.
	</li>
	<li>
		نخزّن في شيفرة جافا سكريبت مرجعًا إلى العنصر <code>&lt;select&gt;</code> وآخر للفقرة النصية <code>&lt;p&gt;</code> ونضيف مترصد أحداث إلى <code>&lt;select&gt;</code> كي يستدعي الدالة <code>()setWeather</code> عندما تتغير قيمته (يتغير الخيار).
	</li>
	<li>
		عندما تُنفَّذ هذه الدالة، تُسند إلى المتغير <code>choice</code> قيمة العنصر <code>&lt;select&gt;</code> ثم نستخدم عبارة شرطية لعرض نصوص مختلفة ضمن الفقرة النصية وفقًا لقيمة المتغير <code>choice</code>. لاحظ كيف اختُبرت كل الشروط باستخدام الكتلة <code>{}()else if</code> ما عدا الشرط اﻷول الذي استخدمنا في اختباره <code>{}()if</code>.
	</li>
	<li>
		أما آخر الخيارات فقد وضع ضمن الكتلة <code>{} else</code> ليكون الملاذ اﻷخير الذي تُنفّذ الشيفرة التي يضمها إن فشلت جميع الاختبارات السابقة. إذ تفرغ شيفرة هذه الكتلة النص الموجود في الفقرة النصية إن لم يختار المستخدم أيًا من خيارات العنصر <code>&lt;select&gt;</code> أي أعاد استخدام الخيار "--Make a choice--" الذي يُعرض افتراضيًا.
	</li>
</ol>

<h3 id="-3">
	ملاحظة حول عوامل المقارنة
</h3>

<p>
	تُستخدم عوامل المقارنة للتحقق من صحة شرط العبارة الشرطية. ولو عدنا إلى المقال الذي يشرح [العوامل الرياضية]() سنجد الخيارات التالية:
</p>

<ul>
	<li>
		<code>===</code> و <code>!==</code> لاختبار تطابق قيمة أو عدم تطابقها مع قيمة أخرى.
	</li>
	<li>
		<code>&lt;</code> و <code>&gt;</code> لاختبار ما إذا كانت قيمة ما أكبر تمامًا أو أصغر تمامًا من أخرى.
	</li>
	<li>
		<code>&lt;=</code> و <code>&gt;=</code> لاختبار ما إذا كانت قيمة ما أكبر أو تساوي أو أصغر أو تساوي قيمة أخرى.
	</li>
</ul>

<p>
	نريد هنا اﻹشارة بشكل خاص إلى اختبار القيم المنطقية (<code>true</code> و <code>false</code>) ونموذج شائع الاستخدام في ذلك. تُعيد أية قيمة ليست إحدى القيم التالية: <code>false</code> أو <code>undefined</code> أو <code>null</code> أو <code>0</code> أو <code>NaN</code> أو (<code>''</code>) القيمة <code>true</code> عندما تستخدم كشرط في عبارة شرطية، وبالتالي بإمكانك استخدام اسم لمتغير لاختبار وجوده أو إن كانت قيمته <code>true</code>.
</p>

<p>
	إليك مثالًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_24" style=""><span class="kwd">let</span><span class="pln"> cheese </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Cheddar"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">cheese</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Yay! Cheese available for making cheese on toast."</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"No cheese on toast for you today."</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وبالعودة إلى مثالنا السابق حول الطفل الذي يؤدي عملًا لوالديه، يمكن إعادة كتابة المثال كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_26" style=""><span class="kwd">let</span><span class="pln"> shoppingDone </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> childsAllowance</span><span class="pun">;</span><span class="pln">

</span><span class="com">//'shoppingDone === true' لا نريد أن نقول صراحة أن</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">shoppingDone</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  childsAllowance </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  childsAllowance </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3 id="ifelse-2">
	كتل <code>if..else</code> متداخلة
</h3>

<p>
	باﻹمكان وضع الكتلة <code>if...else</code> ضمن كتلة <code>if...else</code> أخرى. إذ يمكننا مثلًا كتابة تمرين التوقعات الجوية ليعرض مجموعة أخرى من الخيارات وفقًا لدرجة الحرارة أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_28" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"sunny"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">temperature </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">86</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">It</span><span class="pln"> is $</span><span class="pun">{</span><span class="pln">temperature</span><span class="pun">}</span><span class="pln"> degrees outside </span><span class="pun">—</span><span class="pln"> nice and sunny</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Let</span><span class="str">'</span><span class="pln">s go out to the beach</span><span class="pun">,</span><span class="pln"> or the park</span><span class="pun">,</span><span class="pln"> and </span><span class="kwd">get</span><span class="pln"> an ice cream</span><span class="pun">.`;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">temperature </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">86</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">It</span><span class="pln"> is $</span><span class="pun">{</span><span class="pln">temperature</span><span class="pun">}</span><span class="pln"> degrees outside </span><span class="pun">—</span><span class="pln"> REALLY HOT</span><span class="pun">!</span><span class="pln"> </span><span class="typ">If</span><span class="pln"> you want to go outside</span><span class="pun">,</span><span class="pln"> make sure to put some sunscreen on</span><span class="pun">.`;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستعمل الشيفرة ككل بتناسق مع بعضها، لكن كل عبارة <code>if...else</code> تعمل بشكل منفصل تمامًا عن اﻷخرى.
</p>

<h3 id="andornot">
	العوامل المنطقية: AND و OR و NOT
</h3>

<p>
	إن أردت اختبار عدة شروط دون أن تكتب عبارات متداخلة، يمكنك استخدام العوامل المنطقية وهي:
</p>

<ul>
	<li>
		العامل AND <code>&amp;&amp;</code>: يسمح لك بربط عبارتين أو أكثر وينبغي أن تكون نتيجة جميع هذه العبارات <code>true</code> حتى تعيد العبارة الشرطية النتيجة <code>true</code>.
	</li>
	<li>
		العامل OR <code>||</code>: يسمح لك بربط عبارتين أو أكثر وينبغي أن تكون نتيجة إحدى هذه العبارات <code>true</code> حتى تعيد العبارة الشرطية النتيجة <code>true</code>.
	</li>
</ul>

<p>
	وللتعرف على عمل AND، سنعيد كتابة المثال السابق باستخدامها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_30" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"sunny"</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> temperature </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">86</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">It</span><span class="pln"> is $</span><span class="pun">{</span><span class="pln">temperature</span><span class="pun">}</span><span class="pln"> degrees outside </span><span class="pun">—</span><span class="pln"> nice and sunny</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Let</span><span class="str">'</span><span class="pln">s go out to the beach</span><span class="pun">,</span><span class="pln"> or the park</span><span class="pun">,</span><span class="pln"> and </span><span class="kwd">get</span><span class="pln"> an ice cream</span><span class="pun">.`;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"sunny"</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> temperature </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">86</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">It</span><span class="pln"> is $</span><span class="pun">{</span><span class="pln">temperature</span><span class="pun">}</span><span class="pln"> degrees outside </span><span class="pun">—</span><span class="pln"> REALLY HOT</span><span class="pun">!</span><span class="pln"> </span><span class="typ">If</span><span class="pln"> you want to go outside</span><span class="pun">,</span><span class="pln"> make sure to put some sunscreen on</span><span class="pun">.`;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُنفَّذ الكتلة البرمجية اﻷولى إن أعاد الاختبار (<code>choice === 'sunny'</code> and <code>temperature &lt; 86</code>) النتيجة <code>true</code>.
</p>

<p>
	لنلق نظرة اﻵن على مثال سريع عن استخدام OR:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_32" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">iceCreamVanOutside </span><span class="pun">||</span><span class="pln"> houseStatus </span><span class="pun">===</span><span class="pln"> </span><span class="str">"on fire"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"You should leave the house quickly."</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Probably should just stay in then."</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أما النوع اﻷخير من العوامل المنطقة NOT والذي يعبّر عنه بالمحرف <code>!</code>، فيُستخدم لنفي عبارة، إليك المثال السابق بوجود عامل النفي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_34" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!(</span><span class="pln">iceCreamVanOutside </span><span class="pun">||</span><span class="pln"> houseStatus </span><span class="pun">===</span><span class="pln"> </span><span class="str">"on fire"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Probably should just stay in then."</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"You should leave the house quickly."</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	فإن أعادت العبارة OR القيمة <code>true</code> سينفيها العامل NOT وستعيد العبارة الكاملة القيمة <code>false</code>.
</p>

<p>
	بإمكانك دمج العدد الذي تساء من العوامل المنطقية مع بعضها إن أردت ووفقًا للبنية البرمجية التي تريدها. إليك مثالًا تُنفَّذ فيه شيفرة الكتلة إذا أعادت كلتا عبارتي OR القيمة <code>true</code> أي عندما تعيد العبارة الكلية AND القيمة <code>true</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_36" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">x </span><span class="pun">===</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> y </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> z </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">loggedIn </span><span class="pun">||</span><span class="pln"> userName </span><span class="pun">===</span><span class="pln"> </span><span class="str">"Steve"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// run the code</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	من اﻷخطاء الشائعة المرتكبة عند استخدام العامل OR في العبارات الشرطية هو كتابة المتغير الذي تريد التحقق من حالته، ثم كتابة قائمة من القيم التي تريد موازنتها بالمتغير يفصل بينها العامل OR (<code>||</code>) كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_38" style=""><span class="com">// OR استخدام خاطئ للعامل</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x </span><span class="pun">===</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="lit">7</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// run my code</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	في هذه الحالة ستكون نتيجة الشرط داخل <code>()if</code> صحيحة دائمًا لأن الرقم 7 أو أي عدد غير معدوم سيعطي النتيجة <code>true</code> ويُفهم اﻷمر على النحو " إذا كان x مساويًا 5 أو 7 ستكون النتيجة <code>true</code>" وهذا أمر محقق دائمًا (كون x متغير غير محدد القيمة). لكنك لا تريد هذه النتيجة منطقيًا، وعليك تصحيح الكود السابق على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_40" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x </span><span class="pun">===</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> x </span><span class="pun">===</span><span class="pln"> </span><span class="lit">7</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> x </span><span class="pun">===</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> x </span><span class="pun">===</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// run my code</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2 id="switch">
	عبارة الاختيار المتعدد <code>switch</code>
</h2>

<p>
	تؤدي عبارة <code>if</code> واجبها تمامًا في اختبار الشروط، لكن لا يخلو اﻷمر من بعض السلبيات. فهي أسلوب جيد عندما تكون أمام خيارات محدودة يتضمن كل منها كمية معقولة من الشيفرة، أو عندما يكون الشرط مركبًا ويضم عدة عوامل موازنة منطقية. لكن في الحالات التي تريد فيا إسناد قيمة إلى متغير أو طباعة عبارة محددة عند تحقق شرط معين، ستكون الشيفرة طويلة وخاصة إن كان أمامك عدد كبير من الخيارات.
</p>

<p>
	تظهر في حالات كهذه فائدة البنية <code>switch</code> التي تأخذ عبارة أو قيمة واحدة ثم تبحث عن هذه القيمة أو الشرط بين الخيارات المتعددة المتاحة حتى تجد المطلوب وتنفذ عندها الشيفرة التي يضمها الخيار المطابق. إليك قالب استخدام <code>switch</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_42" style=""><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">expression</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">case</span><span class="pln"> choice1</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// run this code</span><span class="pln">
    </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">case</span><span class="pln"> choice2</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// run this code instead</span><span class="pln">
    </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// include as many cases as you like</span><span class="pln">

  </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// actually, just run this code</span><span class="pln">
    </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لدينا في الكود السابق:
</p>

<ol>
	<li>
		الكلمة المحجوزة <code>switch</code> يليها قوسان.
	</li>
	<li>
		عبارة أو قيمة ضمن القوسين.
	</li>
	<li>
		الكلمة المحجوزة <code>case</code> يتبعها خيار يمثل ما يمكن أن تكونه العبارة أو القيمة التي تشير إليها.
	</li>
	<li>
		شيفرة تُنفَّذ إن طابق الخيار العبارة أو القيمة.
	</li>
	<li>
		الكلمة المحجوزة <code>break</code> تليها فاصلة منقوطة كي يتوقف المتصفح عن التحقق من بقية الخيارات عندما يجد الخيار المطابق ويتابع تنفيذ الشيفرة ما بعد الكتلة <code>switch</code>.
	</li>
	<li>
		تكرار للبنية <code>case</code> وفقًا لعدد الخيارات الموجودة.
	</li>
	<li>
		الكلمة المحجوزة <code>default</code> يليها نمط الشيفرة الموجود في أي حالة <code>case</code> أخرى ما عدا أن <code>default</code> لا يتبعها خيار محدد ولا تحتاج إلى التعليمة <code>break</code> لأنها آخر ما يُنفّذ في عبارة <code>switch</code> ويمثّل الخيار الافتراضي إن أخفق التطابق مع جميع الخيارات المتاحة.
	</li>
</ol>

<p>
	<strong>ملاحظة:</strong> لا حاجة لوجود الجزء <code>default</code> وبإمكانك حذفه إن كنت متأكدًا تمامًا من وجود حالة تطابق. لكن إن أمكن وجود حالة عدم تطابق لا بد من تضمينها لمعالجة الحالات المجهولة.
</p>

<h3 id="switch-1">
	مثال عن كتلة <code>switch</code>
</h3>

<p>
	لنلق نظرة اﻵن على مثال واقعي، يُظهر استخدام الكتلة <code>switch</code> في تطبيق الأحوال الجوية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5790_44" style=""><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"weather"</span><span class="tag">&gt;</span><span class="pln">Select the weather type today: </span><span class="tag">&lt;/label&gt;</span><span class="pln">
</span><span class="tag">&lt;select</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"weather"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">""</span><span class="tag">&gt;</span><span class="pln">--Make a choice--</span><span class="tag">&lt;/option&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"sunny"</span><span class="tag">&gt;</span><span class="pln">Sunny</span><span class="tag">&lt;/option&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"rainy"</span><span class="tag">&gt;</span><span class="pln">Rainy</span><span class="tag">&lt;/option&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"snowing"</span><span class="tag">&gt;</span><span class="pln">Snowing</span><span class="tag">&lt;/option&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"overcast"</span><span class="tag">&gt;</span><span class="pln">Overcast</span><span class="tag">&lt;/option&gt;</span><span class="pln">
</span><span class="tag">&lt;/select&gt;</span><span class="pln">

</span><span class="tag">&lt;p&gt;&lt;/p&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_46" style=""><span class="kwd">const</span><span class="pln"> select </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"select"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> para </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">

select</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"change"</span><span class="pun">,</span><span class="pln"> setWeather</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> setWeather</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> choice </span><span class="pun">=</span><span class="pln"> select</span><span class="pun">.</span><span class="pln">value</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">choice</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"sunny"</span><span class="pun">:</span><span class="pln">
      para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln">
        </span><span class="str">"It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream."</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"rainy"</span><span class="pun">:</span><span class="pln">
      para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln">
        </span><span class="str">"Rain is falling outside; take a rain coat and an umbrella, and don't stay out for too long."</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"snowing"</span><span class="pun">:</span><span class="pln">
      para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln">
        </span><span class="str">"The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman."</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"overcast"</span><span class="pun">:</span><span class="pln">
      para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln">
        </span><span class="str">"It isn't raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case."</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
      para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2 id="-4">
	العامل الثلاثي Ternary operator
</h2>

<p>
	نريد أخيرًا المرور على صيغة أخيرة للعبارات الشرطية قبل الانتقال إلى التمارين وهي العامل الثلاثي الذي يختبر شرطًا واحدًا ويعيد قيمة أو عبارة إن كان الشرط محققًا وقيمة أو عبارة أخرى إن لم يكن محققًا. لهذا العامل فائدته في بعض الحالات ويحتاج إلى شيفرة أقل من كتلة <code>if...else</code> في حال كان لديك خيارين اثنين لانتقاء أحدهما وفقًا لنتيجة من الشكل <code>true</code>/<code>false</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_48" style=""><span class="pln">condition </span><span class="pun">?</span><span class="pln"> run </span><span class="kwd">this</span><span class="pln"> code </span><span class="pun">:</span><span class="pln"> run </span><span class="kwd">this</span><span class="pln"> code instead</span></pre>

<p>
	إليك مثالًا بسيطًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_50" style=""><span class="kwd">const</span><span class="pln"> greeting </span><span class="pun">=</span><span class="pln"> isBirthday
  </span><span class="pun">?</span><span class="pln"> </span><span class="str">"Happy birthday Mrs. Smith — we hope you have a great day!"</span><span class="pln">
  </span><span class="pun">:</span><span class="pln"> </span><span class="str">"Good morning Mrs. Smith."</span><span class="pun">;</span></pre>

<p>
	تعرض الشيفرة متغيرًا يُدعى <code>isBirthday</code> فإن كانت قيمته <code>true</code> يُحييا الضيف برسالة معايدة بعيد ميلاده، أما إن كانت قيمته <code>false</code> فيُحييا بالتحية الاعتيادية.
</p>

<h3 id="-5">
	مثال عن العامل الثلاثي
</h3>

<p>
	لا تُستخدم المتغيرات فقط مع العامل الثلاثي، بل يستطيع أن ينفذ دوال أو أسطر متعددة من الشيفرة. ولتوضيح الأمر، يعرض المثال التالي برنامجًا لاختيار سمة لتنسيق موقع ويب باستخدام العامل الثلاثي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5790_54" style=""><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"theme"</span><span class="tag">&gt;</span><span class="pln">Select theme: </span><span class="tag">&lt;/label&gt;</span><span class="pln">
</span><span class="tag">&lt;select</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"theme"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"white"</span><span class="tag">&gt;</span><span class="pln">White</span><span class="tag">&lt;/option&gt;</span><span class="pln">
  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"black"</span><span class="tag">&gt;</span><span class="pln">Black</span><span class="tag">&lt;/option&gt;</span><span class="pln">
</span><span class="tag">&lt;/select&gt;</span><span class="pln">

</span><span class="tag">&lt;h1&gt;</span><span class="pln">This is my website</span><span class="tag">&lt;/h1&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5790_56" style=""><span class="kwd">const</span><span class="pln"> select </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"select"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> html </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"html"</span><span class="pun">);</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">padding </span><span class="pun">=</span><span class="pln"> </span><span class="str">"10px"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> update</span><span class="pun">(</span><span class="pln">bgColor</span><span class="pun">,</span><span class="pln"> textColor</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  html</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">backgroundColor </span><span class="pun">=</span><span class="pln"> bgColor</span><span class="pun">;</span><span class="pln">
  html</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">color </span><span class="pun">=</span><span class="pln"> textColor</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

select</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"change"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln">
  select</span><span class="pun">.</span><span class="pln">value </span><span class="pun">===</span><span class="pln"> </span><span class="str">"black"</span><span class="pln">
    </span><span class="pun">?</span><span class="pln"> update</span><span class="pun">(</span><span class="str">"black"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"white"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">:</span><span class="pln"> update</span><span class="pun">(</span><span class="str">"white"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"black"</span><span class="pun">),</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="300" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/vYMLMpj?default-tab=result" style="width: 100%;" title="js-making-decisions2">See the Pen js-making-decisions2 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<p>
	لدينا في الشيفرة السابقة العنصر <code>&lt;select&gt;</code> الذي يُستخدم في اختيار سمة (أحد اللونين اﻷبيض أو اﻷسود)، إضافة إلى عنصر عنوان من المستوى اﻷول <code>&lt;h1&gt;</code> لعرض عنوان صفحة الويب. كما لدينا الدالة <code>()update</code> التي تأخذ لونين كمعاملين لها. تضبط الدالة لون خلفية الصفحة لتصبح اللون الأول ولون النص هو اللون الثاني. نلاحظ أخيرًا استخدام مترصّد اﻷحداث <code>onChange</code> الذي ينُفِّذ الدالة مع معاملين هما اللونين اﻷسود واﻷبيض. يبدأ البرنامج بالعبارة الشرطية <code>select.value === 'black'</code> وبعدها تُنفّذ الدالة <code>()update</code> ومعاملاها اللونان اﻷسود واﻷبيض، إذا كانت النتيجة <code>true</code> وبالتالي تصبح الخلفية سوداء والنص أبيض. أما إن أعاد الشرط السابق القيمة <code>false</code>، تُنفَّذ الدالة <code>()update</code> ومعاملاها اللونان الأبيض واﻷسود فتكون الخلفية بيضاء والنص أسود اللون.
</p>

<h2 id="-6">
	مثال عل إنشاء تقويم زمني بسيط
</h2>

<p>
	سننشئ تطبيق تطبيق تقويم زمني بسيط يتيح للمستخدم الاختيار بين اﻷشهر المختلفة المستخدم ليعرض تقويم مناسب للشهر. 
</p>

<p>
	إذا كان لدينا تصميم الصفحة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7364_8" style=""><span class="tag">&lt;h2&gt;</span><span class="pln">Live output</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
</span><span class="tag">&lt;iframe</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"output"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"100%"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"600px"</span><span class="tag">&gt;&lt;/iframe&gt;</span><span class="pln">

</span><span class="tag">&lt;h2&gt;</span><span class="pln">Editable code</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
</span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"a11y-label"</span><span class="tag">&gt;</span><span class="pln">
  Press Esc to move focus away from the code area (Tab inserts a tab character).
</span><span class="tag">&lt;/p&gt;</span><span class="pln">

</span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"code"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"playable-code"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">400px</span><span class="pun">;</span><span class="kwd">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">95%</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
const select = document.querySelector('select');
const list = document.querySelector('ul');
const h1 = document.querySelector('h1');

select.addEventListener('change', () =&gt; {
  const choice = select.value;

  // ADD CONDITIONAL HERE

  createCalendar(days, choice);
});

function createCalendar(days, choice) {
  list.innerHTML = '';
  h1.textContent = choice;
  for (let i = 1; i &lt;= days; i++) {
    const listItem = document.createElement('li');
    listItem.textContent = i;
    list.appendChild(listItem);
  }
}

createCalendar(31, 'January');
</span><span class="tag">&lt;/textarea&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"playable-buttons"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"reset"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Reset"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"solution"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Show solution"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	لنضف بعض التنسيقات كما يلي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_7364_10" style=""><span class="pln">html </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">font-family</span><span class="pun">:</span><span class="pln"> sans-serif</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

h2 </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">font-size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">16px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">a11y-label </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">text-align</span><span class="pun">:</span><span class="pln"> right</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">font-size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.7rem</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">98%</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

body </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">background</span><span class="pun">:</span><span class="pln"> </span><span class="lit">#f5f9fa</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هذا كود جافا سكريبت المطلوب لعمل التقويم الزمني بالشكل المناسب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7364_15" style=""><span class="kwd">const</span><span class="pln"> select </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"select"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> list </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"ul"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> h1 </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"h1"</span><span class="pun">);</span><span class="pln">

select</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"change"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> choice </span><span class="pun">=</span><span class="pln"> select</span><span class="pun">.</span><span class="pln">value</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> days </span><span class="pun">=</span><span class="pln"> </span><span class="lit">31</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"February"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    days </span><span class="pun">=</span><span class="pln"> </span><span class="lit">28</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"April"</span><span class="pln"> </span><span class="pun">||</span><span class="pln">
    choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"June"</span><span class="pln"> </span><span class="pun">||</span><span class="pln">
    choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"September"</span><span class="pln"> </span><span class="pun">||</span><span class="pln">
    choice </span><span class="pun">===</span><span class="pln"> </span><span class="str">"November"</span><span class="pln">
  </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    days </span><span class="pun">=</span><span class="pln"> </span><span class="lit">30</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  createCalendar</span><span class="pun">(</span><span class="pln">days</span><span class="pun">,</span><span class="pln"> choice</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> createCalendar</span><span class="pun">(</span><span class="pln">days</span><span class="pun">,</span><span class="pln"> choice</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  list</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  h1</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> choice</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">let</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> days</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> listItem </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"li"</span><span class="pun">);</span><span class="pln">
    listItem</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
    list</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">listItem</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

createCalendar</span><span class="pun">(</span><span class="lit">31</span><span class="pun">,</span><span class="pln"> </span><span class="str">"January"</span><span class="pun">);</span></pre>

<p>
	كما تلاحظ في الكود أعلاه فقد استخدمنا معالج أحداث <code>onchange</code> يرصد تغيّر قيمة العنصر الذي يختاره المستخدم من العنصر <code>&lt;select&gt;، </code>وكتبنا عبارة شرطية ضمن دالة معالج الأحداث <code>onchange</code> مهمتها ما يلي:
</p>

<ol>
	<li>
		النظر إلى الشهر المختار المُخزَّن في المتغير <code>choice</code> وهو قيمة العنصر <code>&lt;select&gt;</code>.
	</li>
	<li>
		ضبط المتغيّر <code>days</code> كي يكون مساويًا لعدد أيام الشهر المختار.
	</li>
</ol>

<p>
	وهذه النتيجة التي ستحصل عليها:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="146547" href="https://academy.hsoub.com/uploads/monthly_2024_03/calender.png.f754f6826f6ad4bf3a60bd848cc4b6f4.png" rel=""><img alt="calender.png" class="ipsImage ipsImage_thumbnailed" data-fileid="146547" data-ratio="29.04" data-unique="an93pxtn1" style="width: 699px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2024_03/calender.thumb.png.150e5e858378f2606fb401195d75c85f.png"></a>
</p>

<h2>
	تطبيق عملي: خيارات لونية أكثر
</h2>

<p>
	ستحوّل في هذا التمرين العامل الثلاثي الذي تعرفنا عليه سابقًا إلى عبارة <code>switch</code> كي نتمكن من تطبيق خيارات أكثر على موقع الويب البسيط الذي نعمل عليه. لاحظ أن العنصر <code>&lt;select&gt;</code> لا يضم خيارين فقط بل خمسة، لهذا لا بد من استخدام <code>switch</code> هذه المرة تحت التعليق <code>ADD SWITCH STATEMENT//</code>:
</p>

<ul>
	<li>
		يجب أن تقبل العبارة المتغير <code>choice</code> ليكون عبارة الدخل.
	</li>
	<li>
		يجب أن تُوازن قيمة المتغير <code>choice</code> في كل حالة مع أحد الخيارات <code>&lt;option&gt;</code> وهي <code>white</code> أو <code>black</code> أو <code>purple</code> أو  <code>yellow</code><br>
		أو <code>psychedelic</code>.
	</li>
	<li>
		يجب تنفيذ الدالة <code>()update</code> في كل حالة وذلك بتمرير قيمتين لونيتين لها تمثّل اﻷولى لون الخلفية والثانية لون النص، وتذكر أن هذه القيم نصيّة ولا بد من وضعها ضمن إشارتي تنصيص.
	</li>
</ul>

<p>
	إذا ارتكبت خطأ، يمكنك دائمًا إعادة تعيين المثال باستخدام زر "Reset" الموجود في نهاية الإطار التالي، وإذا واجهتك مشكلة في حل السؤال بنفسك، فاضغط على زر "Show solution"  لرؤية الحل الصحيح.
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="600" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/wvZMZmZ?default-tab=result" style="width: 100%;" title=" js-making-decisions4">See the Pen js-making-decisions4 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<h2 id="-8">
	الخلاصة
</h2>

<p>
	قدمنا في هذا المقال كل ما تحتاج معرفته حاليًا عن البنى الشرطية في جافا سكريبت، راجع المقال مرارًا لترسّخ المعلومات التي حصلت عليها في ذهنك أو بإمكانك طرح اﻷسئلة التي تشاء في نقاش صفحة المقال ضمن أكاديمية حسوب.
</p>

<p>
	ترجمة -وبتصرف- لمقال: <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/conditionals" rel="external nofollow">Making decisions in your code-conditionals</a>
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2308/" rel="">المصفوفات في جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D8%B1%D9%91%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D9%85%D9%86%D8%B8%D9%88%D8%B1-%D8%B9%D8%A7%D9%85-r2266/" rel="">تعرّف على لغة جافا سكريبت من منظور عام</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%B5%D9%81%D8%B1-%D8%AD%D8%AA%D9%89-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81-r2046/" rel="">تعلم لغة جافا سكريبت من الصفر حتى الاحتراف</a>
	</li>
	<li>
		<a href="http://%20%D8%AF%D9%84%D9%8A%D9%84%20%D8%AA%D8%B9%D9%84%D9%85%20%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA%20%D8%A7%D9%84%D9%85%D8%B9%D8%A7%D9%85%D9%84%D8%A7%D8%AA%20%D8%A7%D9%84%D9%85%D9%86%D8%B7%D9%82%D9%8A%D8%A9%20%D9%81%D9%8A%20%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA%20" rel="external nofollow">المعاملات المنطقية في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AC%D9%85%D9%84-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-ifelse-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r616/" rel="">الجمل الشرطية if/else في جافاسكريبت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2271</guid><pubDate>Mon, 11 Mar 2024 12:07:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x631;&#x651;&#x641; &#x639;&#x644;&#x649; &#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x644;&#x63A;&#x629; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A; &#x645;&#x646; &#x645;&#x646;&#x638;&#x648;&#x631; &#x639;&#x627;&#x645;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D8%B1%D9%91%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D9%85%D9%86%D8%B8%D9%88%D8%B1-%D8%B9%D8%A7%D9%85-r2266/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_03/--.png.4203b4a7c5716c56714711b7857e4518.png" /></p>
<p>
	سنلقي نظرة في هذا المقال على جافا سكريبت JavaScript من منظور عام ونجيب على أسئلة مثل "ما هي جافا سكريبت؟" و "ماذا تفعل هذه اللغة؟" لنتأكد أنك تملك الفهم الجيد لهذه اللغة بالعموم قبل الغوص في التفاصيل الأكثر تعقيدًا.
</p>

<p>
	لن تحتاج أية معرفة مسبقة بلغة جافا سكربت لتتابع معنا، لكن عليك قبل البدء بقراءة هذا المقال أن تمتلك بعض المعرفة بالأمور التالية:
</p>

<ol>
	<li>
		معرفة ببعض أساسيات <a href="https://wiki.hsoub.com/HTML" rel="external" target="_blank">HTML</a> و <a href="https://wiki.hsoub.com" rel="external" target="_blank">CSS</a>، لهذا ننصحك بالاطلاع على بعض المقالات السابقة مثل:
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/html/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-html-r1687/" rel="">أساسيات HTML</a>.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/css/%D8%AA%D8%B9%D8%B1%D9%91%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-css-r70/" rel="">أساسيات عمل CSS</a>.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%B9%D8%A7%D9%84%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D9%85%D8%B9%D8%A7%D9%8A%D9%8A%D8%B1%D9%87-r1670/" rel="">عالم الويب ومعاييره</a>.
	</li>
</ol>

<p>
	<strong>ملاحظة</strong>: إن كنت تعمل على حاسوب أو جهاز لوحي أو أجهزة أخرى لا تسمح لك بإنشاء ملفات خاصة بك، يمكن تجريب معظم الأمثلة والشيفرات ضمن محرر برمجي عبر الإنترنت مثل JSBin أو Glitch.
</p>

<h2 id="-1">
	ما هي لغة جافا سكريبت
</h2>

<p>
	<a href="https://wiki.hsoub.com/JavaScript" rel="external" target="_blank">لغة جافا سكريبت</a> هي لغة برمجة تسمح لك بتنفيذ ميزات عديدة في صفحات الويب. ترى ذلك في الصفحات التي لا تكتفي بعرض معلومات ثابتة أو تلك التي تحدّث محتواها تلقائيًا مع الوقت أو تعرض خرائط تفاعلية أو رسوم ثنائية وثلاثية البعد. تُعد جافا سكريبت الطبقة الثالثة من طبقات الكعكة التي تمثّل تقنيات الويب المعيارية أما الطبقتان الباقيتين فهما <a href="https://wiki.hsoub.com/HTML" rel="external" target="_blank">HTML</a> و <a href="https://wiki.hsoub.com/CSS" rel="external" target="_blank">CSS</a>، وقد غطينا المفاهيم المتعلقة بهما في مقالات سابقة من سلسلة <a href="https://academy.hsoub.com/tags/%D8%AA%D8%B9%D9%84%D9%85%20%D8%AA%D8%B7%D9%88%D9%8A%D8%B1%20%D8%A7%D9%84%D9%88%D9%8A%D8%A8/" rel="">تعلم تطوير الويب</a>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145877" href="https://academy.hsoub.com/uploads/monthly_2024_03/01_three_layers_of_web_cake.png.81610fc5a5d9e75daad9d8cb96cb6d40.png" rel=""><img alt="01 three layers of web cake" class="ipsImage ipsImage_thumbnailed" data-fileid="145877" data-unique="78xzurm9j" src="https://academy.hsoub.com/uploads/monthly_2024_03/01_three_layers_of_web_cake.png.81610fc5a5d9e75daad9d8cb96cb6d40.png"> </a>
</p>

<ul>
	<li>
		<strong><a href="https://wiki.hsoub.com/HTML" rel="external" target="_blank">HTML</a></strong>: لغة توصيف تُستخدم لهيكلة صفحات الويب وإعطاء معنى لمحتواها. فهي تعرّف مثلًا المقاطع النصية والعناوين وجداول البيانات والصور والفيديو.
	</li>
	<li>
		<strong><a href="https://wiki.hsoub.com/CSS" rel="external" target="_blank">CSS</a></strong>: هي لغة تنسيق تُطبق قواعد تنسيق محددة على محتوى HTML مثل ضبط ألوان الخلفية وخطوط الكتابة وترتيب المحتوى ضمن عدة أعمدة
	</li>
	<li>
		<strong><a href="https://wiki.hsoub.com/JavaScript" rel="external" target="_blank">جافا سكريبت</a></strong>: لغة برمجة تمكّنك من إنشاء محتوى يُحدّّث ديناميكيًا على صفحات الويب، والتحكم بالوسائط المتعددة وتحريك الصور وكل ما يجعل صفحة الويب تفاعلية (ليس كل شيء تمامًا، لكنها ستذهلك بما يمكن أن تفعله شيفرة مكوّنة من أسطر قليلة)
	</li>
</ul>

<p>
	تُبنى هذه الطبقات فوق بعضها بأناقة، ولنأخذ عنوان نصي بسيط كمثال. سنوصّف ذلك من خلال لغة HTML التي تعطيه الشكل وتصف الغاية منه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2474_6" style=""><span class="tag">&lt;p&gt;</span><span class="pln">Player 1: Chris</span><span class="tag">&lt;/p&gt;</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145878" href="https://academy.hsoub.com/uploads/monthly_2024_03/02_simple-html_struct.png.5c6516b0bb0e116ad8bccda01500c2b5.png" rel=""><img alt="02 simple html struct" class="ipsImage ipsImage_thumbnailed" data-fileid="145878" data-unique="znymwu6su" src="https://academy.hsoub.com/uploads/monthly_2024_03/02_simple-html_struct.png.5c6516b0bb0e116ad8bccda01500c2b5.png"> </a>
</p>

<p>
	يمكننا بعد ذلك إضافة بعض تنسيقات CSS لكي نحسّن المظهر:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_2474_8" style=""><span class="pln">p </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">font-family</span><span class="pun">:</span><span class="pln"> </span><span class="str">"helvetica neue"</span><span class="pun">,</span><span class="pln"> helvetica</span><span class="pun">,</span><span class="pln"> sans-serif</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">letter-spacing</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">text-transform</span><span class="pun">:</span><span class="pln"> uppercase</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">text-align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> solid </span><span class="kwd">rgb</span><span class="pun">(</span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">200</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">0.6</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">background</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">rgb</span><span class="pun">(</span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">200</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">0.6</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">color</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">rgb</span><span class="pun">(</span><span class="lit">255</span><span class="pln"> </span><span class="lit">255</span><span class="pln"> </span><span class="lit">255</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">box-shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> </span><span class="kwd">rgb</span><span class="pun">(</span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">200</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">0.4</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">border-radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3px</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">display</span><span class="pun">:</span><span class="pln"> inline-block</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145879" href="https://academy.hsoub.com/uploads/monthly_2024_03/03_simple_css_style.png.e2a39fd90b9977035b631066510e41d8.png" rel=""><img alt="03 simple css style" class="ipsImage ipsImage_thumbnailed" data-fileid="145879" data-unique="nym8ma0vg" src="https://academy.hsoub.com/uploads/monthly_2024_03/03_simple_css_style.png.e2a39fd90b9977035b631066510e41d8.png"> </a>
</p>

<p>
	وأخيرًا يمكننا إعطاء ديناميكية للصفحة بإضافة شيفرة جافا سكريبت بسيطة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_10" style=""><span class="kwd">const</span><span class="pln"> para </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">

para</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> updateName</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> updateName</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"Enter a new name"</span><span class="pun">);</span><span class="pln">
  para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Player</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">name</span><span class="pun">}`;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="300" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/dyLYMXB?default-tab=result" style="width: 100%;" title="javascript1">See the Pen javascript1 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<p>
	جرّب أن تنقر على العنوان النصي بنسخته الأخيرة وراقب ما سيحدث.
</p>

<p>
	ما تفعله جافا سكريبت حقيقة أكثر من ذلك بكثير، سنستعرض ذلك بتفاصيل أوفى في الفقرات التالية.
</p>

<h2 id="-2">
	ما الذي تستطيعه جافا سكريبت حقيقةً؟
</h2>

<p>
	تتكون لغة جافا سكريبت التي تعمل من ناحية العميل من بعض الميزات البرمجية البنيوية التي تسمح لك بتنفيذ الكثير من الأشياء مثل:
</p>

<ul>
	<li>
		تخزين قيم مهمة ضمن المتغيرات. فما فعلناه في المثال السابق مثلًا أننا طلبنا إدخال اسم جديد ثم خزّنا القيمة المُدخلة في متغيّر سميناه <code>name</code>.
	</li>
	<li>
		العمل على جزء من نص وهو ما يعرف برمجيًا بالسلسلة النصية <a href="https://wiki.hsoub.com/JavaScript/String" rel="external">String</a> فإذ أخذنا في المثال السابق السلسلة النصية " :Player1" وأضفنا إليها قيمة المتغيّر <code>name</code>  يمكننا إنشاء عنوان نصي كامل مثل "Player 1: Chris".
	</li>
	<li>
		تنفيذ شيفرة برمجية استجابةً لحدث معين يقع في صفحة الويب، فقد استخدمنا في المثال السابق الحدث <code>click</code> لالتقاط عملية النقر على العنوان النصي ومن ثم نفذنا الشيفرة التي تُحدّث العنوان بعد إضافة الاسم عليه.
	</li>
	<li>
		وهناك الكثير من الأشياء التي تقوم بها لغة جافا سكريبت أيضًا!
	</li>
</ul>

<p>
	ولعل أكثر الأمور إثارة، هي القدرة الوظيفية الكبيرة لهذه اللغة من طرف العميل والتي تُعرف بواجهة التطبيق البرمجية Application programming Interface واختصارًا <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel=""><abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> والتي تعطي قوة كبيرة في استخدام الشيفرة.
</p>

<p>
	فواجهات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> هي مجموعة معدة سلفًا من الشيفرة التي تسمح للمطور بتنفيذ برامج من الصعب أو المستحيل إنجازها. وما تقدمه هذه الواجهات للشيفرة يشابه ما يمنحه الأثاث والتجهيزات المنزلية للمنزل. فمن السهل أن تأخذ قطع خشبية مقصوصة وجاهزة ثم تجمّعها بالبراغي لتحصل على رف كتب مثلًا بدلًا من أن تصمم كل شيء بنفسك، إذ عليك حينها أن تجد نوع الخشب المناسب ثم تقطع الأخشاب وفق القياس الصحيح والشكل المطلوب وأن تجد البراغي المناسبة ومن ثم تجميعها لتحصل على رف الكتب المطلوب.
</p>

<p>
	وتصنّف واجهات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> عمومًا ضمن فئتين أساسيتين:
</p>

<ol>
	<li>
		واجهات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> الخاصة بالمتصفح
	</li>
	<li>
		واجهات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> يقدمها طرف آخر  Third party <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
	</li>
</ol>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145880" href="https://academy.hsoub.com/uploads/monthly_2024_03/04_categories_of_API.png.fd0e883a7d8824243fca74ab091d4512.png" rel=""><img alt="04 categories of api" class="ipsImage ipsImage_thumbnailed" data-fileid="145880" data-ratio="62.71" data-unique="r023q9rk9" style="width: 700px; height: auto;" width="700" src="https://academy.hsoub.com/uploads/monthly_2024_03/04_categories_of_API.png.fd0e883a7d8824243fca74ab091d4512.png"> </a>
</p>

<p>
	وسنشرح تاليًا آلية عمل كل منهما بمزيد من التفصيل.
</p>

<h3 id="api">
	واجهات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> الخاصة بالمتصفح
</h3>

<p>
	وهي برمجيات مدمجة في بنية المتصفح، قادرة على التعامل مع البيانات في البيئة الحاسوبية أو أن تقوم ببعض العمليات المعقدة المفيدة مثل:
</p>

<ul>
	<li>
		واجهة DOM (أو DOM <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>) وتسمح بالتعامل مع ملفات HTML و CSS كإنشاء وحذف وتغيير شيفرات HTML ديناميكيًا وتطبيق تنسيقات جديدة، فكل مرة ترى فيها نافذة منبثقة تُعرض على المتصفح أو ظهور محتوى جديد في الصفحة هي من فعل واجهة <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">DOM</a>.
	</li>
	<li>
		واجهة الموقع الجغرافي (Geolocation <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>)  تستخلص برمجيات الواجهة معلومات جغرافية عن موقعك، لهذا يستطيع تطبيق خرائط جوجل العثور على موقعك وإظهاره على الخريطة.
	</li>
	<li>
		واجهتا canvas و webGL: اللتان تساعدانك على إنشاء رسومات متحركة ثنائية وثلاثية الأبعاد، وتستطيع تنفيذ أشياء رائعة باستخدامهما.
	</li>
	<li>
		واجهات الفيديو والصوتيات مثل HTMLMediaElement و WebRTC: التي تسمح لك بتنفيذ أشياء مميزة مع الوسائط المتعددة مثل تشغيل مقاطع الصوت والفيديو في صفحة الويب مباشرة أو التقاط بث كاميرا الويب وعرضها على حاسوب آخر.
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: يُفضّل عند تجريب استخدام الواجهات البرمجية استخدام متصفحات حديثة مثل فايرفوكس أو كروم أو إيدج أو أوبيرا. كما عليك الأخذ بعين الاعتبار فكرة اختبار الشيفرة على اكثر من متصفح وخاصة عند الوصول إلى مرحلة تسليم شيفرة الإنتاج بعد إنهاء الشيفرة التجريبية.
</p>

<h3 id="api-1">
	واجهات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> يقدمها طرف ثالث
</h3>

<p>
	لا تُبنى هذه الواجهات ضمن المتصفح افتراضيًا، وعادة ما تحصل على شيفرتها من الويب. ومن الأمثلة عليها
</p>

<ul>
	<li>
		واجهة تويتر Twitter <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>: وتسمح لك بعرض آخر تغريداتك ضمن موقع الويب الخاص بك مثلًا وغيرها من الأشياء.
	</li>
	<li>
		واجهة خرائط جوجل وواجهة OpenStreetMap <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> وتسمحان لك بإدراج خرائط ضمن موقعك الإلكتروني وغيرها من الوظائف.
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: إن الواجهات البرمجية موضوع متقدم، ولن نغطي أيًا منها في حديثنا عن جافا سكريبت، لكن هناك الكثير أيضًا لتتعلمه حول لغة جافا سكريبت، فلا تأخذك الحماسة المفرطة. فلن تكون قادرًا على بناء فيسبوك أو خرائط جوجل أو إنستغرام بعد دراستك جافا سكريبت مدة 24 ساعة! فهنالك الكثير من الأساسيات التي عليك معرفتها أولًا، وهذا ما ستوفره لك سلسلة المقالات التالية حول جافا سكريبت.
</p>

<h2 id="-3">
	ما الذي تفعله جافا سكريبت في صفحة الويب
</h2>

<p>
	سنلقي هنا نظرة على بعض الشيفرة، ونستعرض ما يحدث حقيقةً عندما تنفّذ شيفرة جافا سكريبت في صفحتك.
</p>

<p>
	لنستذكر سريعًا ما يحدث عند تحميل صفحة ويب في متصفح . عندما تحمّل صفحة ويب في متصفحك فإنك تنفّذ شيفرتك (HTML و CSS وجافا سكريبت) ضمن بيئة تنفيذية (نافذة المتصفح)، وهذا أمر مماثل لمعمل يستقبل موادًا أولية (الشيفرة) ويخرج منتجًا (صفحة الويب).
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145881" href="https://academy.hsoub.com/uploads/monthly_2024_03/05_javas_html_css.png.3136ee6fe9e51ad2e8ccd68876d07e01.png" rel=""><img alt="05 javas html css" class="ipsImage ipsImage_thumbnailed" data-fileid="145881" data-ratio="44.86" data-unique="k7mgjxdau" style="width: 700px; height: auto;" width="700" src="https://academy.hsoub.com/uploads/monthly_2024_03/05_javas_html_css.png.3136ee6fe9e51ad2e8ccd68876d07e01.png"> </a>
</p>

<p>
	إن أكثر الاستخدامات شيوعًا لجافا سكريبت هو تعديل شيفرة HTML و CSS ديناميكيًا لتغيير الواجهة من خلال الواجهة البرمجية DOM <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>. ولاحظ أن شيفرة صفحات الويب تُحمّل عمومًا وتنفذ وفق ترتيب ظهورها في الصفحة. وقد تحدث أخطاء إن حُمّلت شيفرة جافا سكريبت ونُفِّذت قبل شيفرة HTML و CSS التي ستُعدّل. سنتعلم لاحقًا في مقالنا كيف نلتف على الموضوع.
</p>

<h3 id="-4">
	أمان المتصفح
</h3>

<p>
	لكل نافذة من نوافذ المتصفح جيب خاص لتنفيذ الشيفرة ويُعرف هذا الجيب ببيئة التنفيذ. ويعني ذلك عمومًا أن الشيفرة في كل نافذة تعمل بشكل منفصل تمامًا عن شيفرة النوافذ الأخرى ولا يمكن أن تؤثر الشيفرة في النافذة مباشرة على الشيفرة التي تجري في النافذة الأخرى أو على موقع ويب آخر. يُعد هذا الأمر مقياسًا جيدًا للأمان، فلو لم يكن الأمر كذلك سيكتب القراصنة شيفرات لسرقة معلومات من مواقع أخرى وغيرها من الأفعال الضارة.
</p>

<p>
	<strong>ملاحظة</strong>: هنالك طريقة لإرسال الشيفرة والبيانات من مختلف المواقع أو النوافذ بطريقة آمنة لكنها تقنيات متقدمة لن نغطيها في هذا المقال لكن يمكنك الاطلاع على مقال <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%AE%D8%A7%D8%B7%D8%A8-%D8%A8%D9%8A%D9%86-%D9%86%D9%88%D8%A7%D9%81%D8%B0-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1250/" rel="">التخاطب بين نوافذ المتصفح عبر جافا سكريبت</a> في <a href="https://academy.hsoub.com" rel="external" target="_blank">أكاديمية حسوب</a>.
</p>

<h3 id="-5">
	ترتيب تنفيذ شيفرة جافا سكريبت
</h3>

<p>
	عندما يصادف المتصفح كتلة من شيفرات جافا سكريبت، سينفّذها عادة بالترتيب من الأعلى إلى الأسفل. ويعني هذا ضرورة الانتباه إلى الترتيب الذي تضع وفقه الأشياء. لنعد على سبيل المثال إلى شيفرة جافا سكريبت في المثال الأول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_14" style=""><span class="kwd">const</span><span class="pln"> para </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">

para</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> updateName</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> updateName</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"Enter a new name"</span><span class="pun">);</span><span class="pln">
  para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Player</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">name</span><span class="pun">}`;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نختار في السطر الأول مقطعًا نصيًا ثم نضيف مترصّد للحدث (مستمع للحدث) في السطر الثالث كي تُنفّذ شيفرة الكتلة البرمجية <code>()updteName</code> (الأسطر من 5-8). تسأل الكتلة البرمجية <code>()updateName</code> (يُدعى هذا النوع القابل للاستخدام المتكرر من الكتل البرمجية دوال functions) أن يُدخل المستخدم اسمًا جديدًا ومن ثم تضع الاسم ضمن الفقرة النصية وتحدّث ما يُعرض على الشاشة. فإن بدلت ترتيب أول سطرين، لن تعمل الشيفرة، بل ستحصل على خطأ تعرضه <a href="https://academy.hsoub.com/programming/workflow/%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D9%85%D8%B7%D9%88%D8%B1%D9%8A-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D8%AF%D9%85%D8%AC%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-r1439/" rel="">طرفية المطوّر في المتصفح</a> وهي <code>typeError: para is undefined</code>. ويعني هذا أن الكائن <code>para</code> غير موجود بعد، ولا يمكن إضافة مترصّد أحداث إليه.
</p>

<p>
	<strong>ملاحظة</strong>: هذا الخطأ شائع الحدوث، لهذا انتبه إلى وجود الكائن في الشيفرة قبل أن تحاول العمل معه.
</p>

<h3 id="-6">
	الشيفرة المفسّرة والمصرّفة
</h3>

<p>
	ربما سمعت بالمصطلحين "مفسّر interpreted" و "مصرّف <a href="https://academy.hsoub.com/programming/c/%D8%A7%D9%84%D9%81%D8%B5%D9%84-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%B5%D8%B1%D9%8A%D9%81-compilation-%D9%81%D9%8A-%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r976/" rel="">compiled</a>" في سياق تعلمك للبرمجة. ففي اللغات المفسّرة تنفّذ الشيفرة من الأعلى إلى الأسفل وتُعاد نتيجة تنفيذ الشيفرة مباشرة، ولا حاجة لنقل الشيفرة إلى شكل آخر قبل أن يُنفّذها المتصفح. إذ يستقبل الشيفرة بشكلها النصي المفهوم من قبل المبرمج ثم يعالجها مباشرة. بينما تحوّل الشيفرة في اللغات المصرّفة إلى شكل آخر قبل أن يُنفّذها الحاسوب. إذ تحوّل مثلًا شيفرة لغتي C أو ++C إلى لغة الآلة التي ينفذها الحاسوب بعد ذلك. وينفّذ البرنامج انطلاقًا من صيغته الثنائية التي تنتج عن تصريف شيفرته المصدرية.
</p>

<p>
	جافا سكريبت هي لغة برمجة مفسّرة خفيفة الحجم، يتلقى المتصفح شيفرتها بشكلها النصي وينفّذه. وإذا أردنا الحديث تقنيًا يمكننا القول أن مفسرّات جافا سكريبت الحديثة تستخدم تقنية تّدعى التصريف عند التنفيذ Just-in-time compiling لتحسين الأداء. إذ تُصرّف شيفرة جافا سكريبت المصدرية إلى شكل ثنائي أسرع في نفس الوقت الذي تُنفّذ فيه الشيفرة وهذا ما يجعل التنفيذ أسرع ما يمكن. مع ذلك لا تزال جافا سكريبت في عداد اللغات المفسّرة لأن التصريف يجري أثناء التنفيذ بدلًا من تصريف الشيفرة مسبقًا. ولكلا نوعي اللغات ميزاته، لكن لن نناقش هذا الموضوع الآن.
</p>

<h3 id="-7">
	شيفرة طرف العميل موازنة مع شيفرة طرف الخادم
</h3>

<p>
	لربما سمعت أيضًا بمصطلحي "طرف الخادم server-side" و "طرف العميل client-side" وخاصة في سياق تعلم تطوير الويب. تُنفّذ شيفرة طرف العميل على حاسوب العميل أو المستخدم، فما يحدث عند استعراض صفحة الويب هو أن المتصفح سينزّل شيفرة طرف العميل ثم ينفذها ويعرضها. وما سنتحدث عنه في سلسلة مقالات جافا سكريبت هو استخدام جافا سكريبت من طرف العميل فقط.
</p>

<p>
	تُنفّذ شيفرة طرف الخادم بالمقابل على الخوادم ثم تُنزّل نتيجة التنفيذ وتُعرض في المتصفح. ومن لغات ويب التي تعمل من طرف الخادم نذكر <a href="https://wiki.hsoub.com/PHP" rel="external">PHP</a> و <a href="https://wiki.hsoub.com/Python" rel="external">Python</a> و <a href="https://wiki.hsoub.com/Ruby" rel="external">Ruby</a> و <a href="https://academy.hsoub.com/programming/c-sharp/dotnet/aspnet/" rel="">ASP.NET</a> وكذلك لغة <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافا سكريبت</a>. إذ يمكن استخدام جافا سكريبت كلغة برمجة من طرف الخادم في بيئة Node.js الشهيرة.
</p>
<iframe allowfullscreen="" class="ipsEmbed_finishedLoading" data-controller="core.front.core.autosizeiframe" data-embedauthorid="3889" data-embedcontent="" data-embedid="embed6122563910" src="https://academy.hsoub.com/files/32-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-nodejs/?do=embed" style="overflow: hidden; height: 470px; max-width: 500px; margin: auto; "></iframe>

<h3 id="-8">
	الشيفرة الديناميكية موازنة مع الشيفرة الساكنة
</h3>

<p>
	تُستخدم كلمة ديناميكي لوصف شيفرة جافا سكريبت من طرف العميل ولغات طرف الخادم، وتشير إلى إمكانية تحديث صفحة الويب أو التطبيق ليعرض أشياء مختلفة في ظروف مختلفة، وتوليد محتوى جديد حسب الحاجة. إذ توُلّد لغات طرف الخادم محتوى جديدًا على الخادم عن طريق سحب البيانات من قواعد البيانات مثلًا، بينما تولّد شيفرة جافا سكريبت المحتوى ديناميكيًا ضمن متصفّح العميل، كأن تنشأ جداول HTML وتملأها بالبيانات التي تطلبها من الخادم ومن ثم تعرض هذه الجداول ضمن صفحة الويب التي يراها المستخدم. قد يكون هناك اختلاف بسيط بين سياقي العمل لكنهما متعلقان ببعضهما، وكلا النهجين (طرف العميل وطرف الخادم) يعملان معًا عادة.
</p>

<p>
	عندما لا تُحدَّث صفحة الويب ديناميكيًا بمحتوى جديد ندعوها ساكنة static، فهي تعرض نفس المحتوى دائمًا.
</p>

<h2 id="-9">
	كيف تضيف شيفرة جافا سكريبت إلى صفحتك؟
</h2>

<p>
	تُضاف شيفرة جافا سكريبت إلى صفحة HTML بنفس الأسلوب الذي تُضاف به شيفرة CSS. إذ تستخدم CSS العنصر <code>&lt;link&gt;</code> لتطبيق ورقة تنسيق خارجية و العنصر <code>&lt;style&gt;</code> لتطبيق ورقة تنسيق داخلية على شيفرة HTML، بينما لا تحتاج جافا سكريبت سوى العنصر <code>&lt;script&gt;</code>. لنلق نظرة على عمله.
</p>

<h3 id="-10">
	شيفرة جافا سكريبت داخلية
</h3>

<ol>
	<li>
		قبل كل شيء، أنشئ نسخة من الملف <a href="https://github.com/mdn/learning-area/blob/main/javascript/introduction-to-js-1/what-is-js/apply-javascript.html" rel="external nofollow" target="_blank">apply-javascript.html</a> على جهازك وخزّنها في مكان مناسب.
	</li>
	<li>
		افتح الملف في متصفحك وضمن المحرر النصي في نفس الوقت. سترى أن شيفرة HTML قد أنشأت صفحة ويب بسيطة تضم زرًا يمكن النقر عليه.
	</li>
	<li>
		اضف الشيفرة التالية ضمن الترويسة في المحرر النصي وقبل وسم النهاية <code>&lt;head/&gt;</code>:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_16" style=""><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="com">// JavaScript goes here</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<ol start="4">
	<li>
		سنضيف الآن بعض شيفرة جافا سكريبت ضمن الوسم <code>&lt;script&gt;</code> وتحت عبارة "JavaScript goes here//" لنجعل الصفحة أكثر حيوية:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_18" style=""><span class="pln">document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"DOMContentLoaded"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">function</span><span class="pln"> createParagraph</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> para </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">
    para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"You clicked the button!"</span><span class="pun">;</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">para</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> buttons </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">"button"</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> button </span><span class="kwd">of</span><span class="pln"> buttons</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    button</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> createParagraph</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span></pre>

<ol start="5">
	<li>
		احفظ الملف وحدّث المتصفّح، وستلاحظ ظهور فقرة نصية تحت الزر عند النقر عليه.
	</li>
</ol>

<p>
	<strong>ملاحظة</strong>: إن رأيت أن المثال لا يعمل كما هو مطلوب، راجع الخطوات السابقة بتأنٍ وتحقق أنك فعلت كل شيء بالشكل الصحيح. هل خزنت الملف بلاحقة <code>html.</code>؟ هل وضعت الوسم <code>&lt;script&gt;</code> قبل وسم النهاية <code>&lt;head/&gt;</code>؟ هل أدخلت شيفرة <a href="https://wiki.hsoub.com/JavaScript" rel="external" target="_blank">جافا سكريبت</a> كما هي تمامًا؟ وانتبه إلى أن جافا سكريبت <strong>حساسة لحالة الأحرف</strong> وعليك إضافة الشيفرات كما هي تمامًا وإلا لن تعمل.
</p>

<h3 id="-11">
	شيفرة جافا سكريبت خارجية
</h3>

<p>
	تعمل الشيفرة السابقة جيدًا، لكن ماذا لو أردت أن تضع تلك الشيفرة في ملف خارجي منفصل؟
</p>

<ol>
	<li>
		أنشئ ملفًا جديدًا في نفس المكان الذي خزّنت فيه ملف HTML ثم سمّه <code>script.js</code>. تأكد أن لاحقة الملف هي <code>js.</code> لأنها الطريقة التي يُعرف بها ملف جافا سكريبت.
	</li>
	<li>
		استبدل الوسم <code>&lt;script&gt;</code> بالوسم التالي:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_20" style=""><span class="pun">&lt;</span><span class="pln">script src</span><span class="pun">=</span><span class="str">"script.js"</span><span class="pln"> defer</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<ol start="3">
	<li>
		ضع الشيفرة التالية في ملف <code>script.js</code>:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_22" style=""><span class="kwd">function</span><span class="pln"> createParagraph</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> para </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">
  para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"You clicked the button!"</span><span class="pun">;</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">para</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> buttons </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">"button"</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> button </span><span class="kwd">of</span><span class="pln"> buttons</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  button</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> createParagraph</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<ol start="4">
	<li>
		احفظ الملف وحدّث المتصفّح وسترى الشيء ذاته، لكن شيفرة جافا سكريبت في هذه الحالة موجودة في ملف خارجي. وهذا عمومًا أمر جيد من ناحية تنظيم الشيفرة وجعلها قابلة للاستخدام ضمن جميع صفحات الموقع، إضافة إلى أن ملفات HTML أسهل قراءة في هذه الحالة دون وجود قطع من الشيفرة مزروعةً ضمنها.
	</li>
</ol>

<h3 id="-12">
	معالجات جافا سكريبت السطرية
</h3>

<p>
	قد تصادف في بعض الحالات شيفرة جافا سكريبت ضمن شيفرة HTML، وسيبدو الأمر مشابهًا لما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_26" style=""><span class="kwd">function</span><span class="pln"> createParagraph</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> para </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">
  para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"You clicked the button!"</span><span class="pun">;</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">para</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2474_28" style=""><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">createParagraph</span><span class="pun">()</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">Click me!</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	جرب هذه النسخة في المحرر التفاعلي:
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="300" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/BaEoKQL?default-tab=result" style="width: 100%;" title="javascript2">See the Pen javascript2 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<p>
	لهذه النسخة العمل ذاته كما في النسختين السابقتين، إلا أن العنصر <code>&lt;button&gt;</code> يضم معالجًا سطريًا هو <code>onclick</code> يفعّل عمل الدالة عند النقر على الزر.
</p>

<p>
	<strong>ننصحك بأن لا تفعل ذلك</strong>، فمن السيء أن تلوّث شيفرة HTML يشيفرة جافا سكريبت، إضافة إلى أنها طريقة غير فعّالة أن تضيف السمة <code>"()onclick="createParagraph</code> في كل زر تريده أن ينفّذ الوظيفة ذاتها.
</p>

<h3 id="addevenetlisterer">
	استخدام الدالة <code>addEvenetListerer</code>
</h3>

<p>
	بدلًا من وضع شيفرة جافا سكريبت ضمن وسوم HTML، من الأفضل استخدام بناء جافا سكريبت صرف. إذ تسمح الدالة <code>()querySelectorAll</code> بانتقاء كل أزرار الصفحة، ومن ثم إسناد معالج أحداث لكل زر من خلال الدالة <code>()addEventListener</code>. إليك الشيفرة اللازمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_30" style=""><span class="kwd">const</span><span class="pln"> buttons </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">"button"</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> button </span><span class="kwd">of</span><span class="pln"> buttons</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  button</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> createParagraph</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	قد تبدو الشيفرة أطول بقليل موازنة باستخدام السمة <code>onclick</code>، لكنها ستعمل مع جميع أزرار الصفحة مهما كان عددها أو مهما أضفت أو أزلت أزرارًا، دون الحاجة إلى تغيير شيفرة جافا سكريبت.
</p>

<p>
	<strong>ملاحظة</strong>: جرّب أن تعدّل في شيفرة الملف <code>apply-javascript.html</code> بإضافة بضعة أزرار إضافية، سترى عندها وبعد تحديث الصفحة أن النقر على أي زر منها سينشئ فقرة نصية.
</p>

<h3 id="-13">
	استراتيجيات تحميل السكربتات في صفحات الويب
</h3>

<p>
	تصادفنا بعض المشاكل تتعلق بتوقيت تحميل السكربتات في صفحة الويب. فلا شيء بالبساطة التي يبدو عليها. ومن المشاكل الشائعة هي تحميل شيفرة HTML كاملة وبالترتيب الذي تظهر عليه ضمن الملف. فإن استخدمت جافا سكريبت للتعامل مع عناصر الصفحة (أو شجرة DOM بدقة)، لن تعمل الشيفرة إن حُّملت وفُسِّرت قبل أن يُحمّل عنصر HTML الذي تستهدفه.
</p>

<p>
	وما حدث في الأمثلة الماضية سواء باستخدام جافا سكربت داخليًا أو خارجيًا هو تحميل الشيفرة وتنفيذها ضمن ترويسة الملف وقبل تفسير أي عنصر من عناصر جسم الملف. قد ينتج عن هذا الأمر خطأ لهذا استخدمنا أسلوبًا للالتفاف حول المشكلة.
</p>

<p>
	لاحظ الأسلوب المستخدم في مثال الشيفرة الداخلية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_32" style=""><span class="pln">document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"DOMContentLoaded"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// …</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	إن مترّصد الأحداث والذي يصغي إلى الحدث <code>DOMContentLoaded</code> في المتصفح، سينتظر اكتمال تحميل وتفسير جسم ملف HTML، ولن تعمل شيفرة <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%B5%D9%81%D8%B1-%D8%AD%D8%AA%D9%89-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81-r2046/" rel="">جافا سكريبت</a> ضمن هذه الكتلة قبل ذلك. وبهذه الطريقة نتفادى الخطأ.
</p>

<p>
	وفي مثال الشيفرة الخارجية، نستخدم ميزة أكثر حداثة لجافا سكريبت لحل المشكلة من خلال السمة <code>defer</code> التي تخبر المتصفح أن عليه إكمال تحميل شيفرة HTML عندما يصل إلى السمة <code>&lt;script&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_35" style=""><span class="pun">&lt;</span><span class="pln">script src</span><span class="pun">=</span><span class="str">"script.js"</span><span class="pln"> defer</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	ستُحمّل شيفرة HTML و جافا سكريبت بالتوازي في هذه الحالة وستعمل الشيفرة جيدًا.
</p>

<p>
	<strong>ملاحظة</strong>: لا حاجة لاستخدام الحدث <code>DOMContentLoaded</code> في الشيفرة الخارجية لأن السمة <code>defer</code> تحل المشكلة. ولم نستخدم السمة <code>defer</code> في الشيفرة الداخلية لأنها تعمل فقط مع السكربت الخارجي.
</p>

<p>
	ومن الحلول القديمة التي استخدمت لحل لهذه المشكلة هو وضع شيفرة جافا سكريبت في نهاية الملف وقبل الموسم <code>&lt;body/&gt;</code> وبالتالي تُحمّل الشيفرة بعد إنتهاء تحميل وتفسير عناصر HTML. أما مشكلة هذا الحل هو إيقاف عمل شيفرة جافا سكريبت حتى يكتمل تحميل شجرة DOM الخاصة بملف HTML، وهذا ما يسبب مشكلة أداء كبيرة في مواقع الويب الأكبر، وسيبطئ الموقع.
</p>

<h4 id="asyncdefer">
	السمة <code>async</code> والسمة <code>defer</code>
</h4>

<p>
	توجد في الواقع طريقتان عصريتان لتفادي مشكلة حجب الشيفرة باستخدام السمتين <code>async</code> و <code>defer</code>، وسنلقي نظرة عليهما.
</p>

<p>
	ستُحمّل السكربتات باستخدام <code>async</code> دون إيقاف تحميل الصفحة أثناء تقدم تحميل السكربت. لكن بمجرد اكتمال تحميل السكربت سيُنفَّذ هذا السكربت مما يمنع تصيير الصفحة، ولن تضمن بأي شكل تنفيذ السكربتات بترتيب محدد. ومن الأفضل استخدام هذه السمة عندما لا تتعلق السكربتات في الصفحة ببعضها البعض ولا بأي سكربت آخر في الصفحة.
</p>

<p>
	وبالنسبة للسكربتات التي تُحمّل باستخدام <code>defer</code> ستُحمّل بالترتيب الذي تظهر فيه ضمن الصفحة، ولن تعمل حتى يكتمل تحميل الصفحة، وهذا مفيد في السكربتات التي تتطلب اكتمال تكوين شجرة DOM الخاصة بالملف (وكمثال عليها السكربتات التي تعدّل عنصر أو أكثر في الصفحة).
</p>

<p>
	إليك تمثيلًا بصريًا لأساليب تحميل السكربتات وما الذي تعنيه لصفحتك:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145882" href="https://academy.hsoub.com/uploads/monthly_2024_03/06_scripting_order.png.21b0120512ffa1e0adc359292306f140.png" rel=""><img alt="06 scripting order" class="ipsImage ipsImage_thumbnailed" data-fileid="145882" data-unique="z4wxtsgr3" src="https://academy.hsoub.com/uploads/monthly_2024_03/06_scripting_order.thumb.png.6246bc8d553256c9d37651befece2e46.png"> </a>
</p>

<p>
	فلو كان لديك مثلًا عناصر <code>&lt;script&gt;</code> التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_37" style=""><span class="pun">&lt;</span><span class="pln">script </span><span class="kwd">async</span><span class="pln"> src</span><span class="pun">=</span><span class="str">"js/vendor/jquery.js"</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">script </span><span class="kwd">async</span><span class="pln"> src</span><span class="pun">=</span><span class="str">"js/script2.js"</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">script </span><span class="kwd">async</span><span class="pln"> src</span><span class="pun">=</span><span class="str">"js/script3.js"</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لا يمكنك الاعتماد على ترتيب تحميل العناصر السابقة، فقد يُحمّل <code>jquery.js</code> قبل أو بعد <code>script2.js</code> و <code>script3.js</code>، وإن حدث ذلك، ستوّلد أية دالة ضمن السكربتين الأخيرين خطأً إن اعتمدت على السكربت <code>jquery</code> لأنه قد لا يكون معرّفًا عند تنفيذها.
</p>

<p>
	لهذا استخدم السمة <code>async</code> إن كان لديك مجموعة من السكربتات التي تعمل في الخلفية وتريد فقط أن تضعها في مكانها المناسب بالسرعة الممكنة. فقد يكون لديك مثلًا ملفات بيانات خاصة بلعبة وتريدها أن تكون جاهزة عندما تبدأ اللعبة فعلًا، إذ لا بد من عرض مقدمة اللعبة وعناوينها والمساهمين فيها دون أن تُحجب حتى يُحمّل السكربت وأثناء ذلك يُحمّل السكربت بهدوء في الخلفية.
</p>

<p>
	وإن أردت تنفيذ السكربتات وفق تسلسل ظهورها (كما في الأسفل)، استخدم السمة <code>defer</code>، وستُنفَّذ حالما يُحمّل السكربت ومحتوى الصفحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_39" style=""><span class="pun">&lt;</span><span class="pln">script defer src</span><span class="pun">=</span><span class="str">"js/vendor/jquery.js"</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">script defer src</span><span class="pun">=</span><span class="str">"js/script2.js"</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">script defer src</span><span class="pun">=</span><span class="str">"js/script3.js"</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	نضمن في المثال الثاني أن <code>jquery.js</code> سيُحمّل قبل <code>script2.js</code> الذي يُحمّل قبل <code>script3.js</code>. ولن تُنفَّذ السكربتات حتى يكتمل تحميل الصفحة، وهذا أمر مفيد إن اعتمدت السكربتات على وجود شجرة DOM جاهزة وفي مكانها.
</p>

<p>
	باختصار:
</p>

<ul>
	<li>
		تخبر السمتان <code>async</code> و <code>defer</code> المتصفح أن يحمّل السكربتات في خيط منفصل بينما تحمّل بقية محتويات الصفحة في خيط مختلف في نفس الوقت وبالتالي لن يُحجب عرض محتوى الصفحة أثناء عملية إحضاره.
	</li>
	<li>
		تُنفّذ السكربتات التي تستخدم السمة <code>async</code> حالما ينتهي تحميلها، وسيحجب هذا عرض محتوى الصفحة أثناء التنفيذ ولا يمكن أن تضمن ترتيب السكربتات التي ستُنفَّذ.
	</li>
	<li>
		تُحمّل السكربتات التي تستخدم السمة <code>defer</code> بالترتيب الذي تظهر فيه وتُنفَّذ بمجرد انتهاء تحميل كل شيء.
	</li>
	<li>
		إن كان لابد من تنفيذ السكربت مباشرة بعد تحميله ولا يتعلق تنفيذه بسكربتات أو عناصر أخرى يفضّل استخدام <code>async</code>.
	</li>
	<li>
		إن كان لا بد من الانتظار حتى ينتهي تفسير الملف واعتمد السكربت على سكربتات أخرى أو على تكوين شجرة DOM الخاصة بالملف، استخدم <code>defer</code> وضع السكربتات (العناصر <code>&lt;script&gt;</code>) بالترتيب الذي تريده حتى يُنفذها المتصفح بنفس الترتيب.
	</li>
</ul>

<h2 id="-14">
	التعليقات في جافا سكريبت
</h2>

<p>
	من الممكن كتابة تعليقات ضمن شيفرة جافا سكريبت كما هو الحال في HTML و CSS، وتُكتب هذه التعليقات لتزويد المطوّرين الذين يقرؤون الشيفرة (أو لك شخصيًا إن عدت إليها بعد فترة) بإرشادات عن طريقة عمل الشيفرة، وبالطبع يتجاهل المتصفح هذه التعليقات ولا يحللها.
</p>

<p>
	يُنصح باستخدام التعليقات ما أمكن فهي مفيدة وخاصة في التطبيقات الضخمة، وهنالك طريقتين لإدراج التعليقات:
</p>

<ul>
	<li>
		على شكل سطر وحيد بعد إشارتي شرطة أمامية <code>//</code>.
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_41" style=""><span class="com">// I am a comment</span></pre>

<ul>
	<li>
		أسطر متعددة مكتوبة بين النصين <code>*/</code> و <code>/*</code>.
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_43" style=""><span class="pln">  </span><span class="com">/*
    I am also
    a comment
  */</span></pre>

<p>
	فمثلًا، يمكن إضافة التعليقات التالية إلى آخر مثال شرحناه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2474_45" style=""><span class="com">// Function: creates a new paragraph and appends it to the bottom of the HTML body.</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> createParagraph</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> para </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">
  para</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"You clicked the button!"</span><span class="pun">;</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">para</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">/*
  1. Get references to all the buttons on the page in an array format.
  2. Loop through all the buttons and add a click event listener to each one.

  When any button is pressed, the createParagraph() function will be run.
*/</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> buttons </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">"button"</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> button </span><span class="kwd">of</span><span class="pln"> buttons</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  button</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> createParagraph</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<strong>ملاحظة:</strong> كثرة التعليقات أفضل عادة من التعليقات القليلة، لكن انتبه إن رأيت نفسك تكتب تعليقات كثيرة لتشرح المتغيرات مثلًا (والتي يجب أن تكون واضحة وبديهية) أو لتشرح عمليات بسيطة (عندها قد تكون شيفرتك معقدة).
</p>

<h2 id="-15">
	خلاصة
</h2>

<p>
	هكذا نكون قد خطونا أولى خطواتنا في جافا سكريبت. فقد بدأنا بتمهيد نظري لنمنحك فكرة عن استخدامات جافا سكريبت واﻷشياء التي يمكن أن تفعلها بها. كما رأينا خلال تقدم المقال بعض اﻷمثلة عن كتابة الشيفرة وتعلمنا كيف نضع الشيفرة في مكانها المناسب ضمن بقية شيفرة موقع الويب، إضافة إلى أشياء عديدة أخرى.<br>
	قد تبدو جافا سكريبت صعبة قليلًا للوهلة الأولى، لكن لا تقلق فما نتعلمه في سلسلة المقالات التالية، سيأخذك خطوة خطوة وبأسلوب واضح حتى تصل إلى المرحلة التي تبني فيها أمثلتك الخاصة باستخدام جافا سكريبت
</p>

<p>
	ترجمة -وبتصرف- لمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript" rel="external nofollow" target="_blank">What's JavaScript</a>
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/javascript/" rel="">تعلم لغة جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1689/" rel="">أساسيات لغة جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%B5%D9%81%D8%B1-%D8%AD%D8%AA%D9%89-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81-r2046/" rel="">تعلم جافا سكريبت من الصفر للاحتراف</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">الدليل السريع إلى لغة البرمجة جافاسكريبت JavaScript</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2266</guid><pubDate>Wed, 06 Mar 2024 12:05:00 +0000</pubDate></item><item><title>&#x628;&#x631;&#x645;&#x62C;&#x629; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x645;&#x644;&#x627;&#x62D;&#x638;&#x627;&#x62A; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Alpine.js</title><link>https://academy.hsoub.com/programming/javascript/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%85%D9%84%D8%A7%D8%AD%D8%B8%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-alpinejs-r2230/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_01/------Alpine.js.png.659cd3000061849e2358d66867101e43.png" /></p>
<p>
	بعد أن تعرفنا على إطار العمل Alpine.js واستخدمناه <a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%86-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-alpinejs-r2229/" rel="">لإنشاء بعض الأمثلة البسيطة</a> حيث تعرفنا على معظم الخصائص التي يتيحها الإطار من موجهات وتوابع وما إلى ذلك، سنقوم في هذا المقال بإنشاء تطبيق شامل عبارة عن تطبيق ملاحظات يتيح إنشاء ملاحظات، تعديلها وحذفها، وسنستخدم في هذا التطبيق التابع <a href="https://alpinejs.dev/globals/alpine-store" rel="external nofollow"><code>Alpine.store</code></a> وهو عبارة عن ميزة في Alpine لإدارة الحالة العامة، يُمكنك التفكير في الأمر على أنه عبارة عن مخزن مشترك بين المكونات بحيث يمكن لأي مكون في الصفحة الوصول لهذا المخزن واستعماله بسهولة عبر الخاصية <code>store$</code>. سنستعمل أيضاً الموجه <code>x-for</code> وهو عبارة عن موجه للعبور على عناصر مصفوفة أو قائمة (سنستخدمه لعرض قائمة الملاحظات)، سنبدأ في البداية باستخدام مصفوفة لتخزين الملاحظات ثم في الأخير سنستخدم الذاكرة المحلية الخاصة بالمتصفح لتخزين البيانات ومزامنتها حتى لا نفقدها بعد كل تحديث للصفحة.
</p>

<h2 id="">
	تصميم التطبيق
</h2>

<p>
	سنستخدم في هذا التطبيق قالب بسيط جاهز مبني على مكتبة TailwindCSS، لن تكون بحاجة إلى معرفة مسبقة بالمكتبة TailwindCSS لبناء التطبيق كما يُمكنك الاعتماد على قالب خاص بك فالشيفرات التي سنكتبها لن تتغير، يُمكنك تحميل ملف القالب design.html من رابط المشروع المرفق في نهاية المقال، أو بإمكانك إنشاء ملف HTML فارغ ثم نسخ الشيفرة التالية إليه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_8" style=""><span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"ar"</span><span class="pln"> </span><span class="atn">dir</span><span class="pun">=</span><span class="atv">"rtl"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"UTF-8"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">http-equiv</span><span class="pun">=</span><span class="atv">"X-UA-Compatible"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"IE=edge"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"viewport"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"width=device-width, initial-scale=1.0"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;link</span><span class="pln"> </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"preconnect"</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://fonts.googleapis.com"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;link</span><span class="pln"> </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"preconnect"</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://fonts.gstatic.com"</span><span class="pln"> </span><span class="atn">crossorigin</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;link</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic:wght@500;700&amp;display=swap"</span><span class="pln"> </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"stylesheet"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">تطبيق ملاحظات</span><span class="tag">&lt;/title&gt;</span><span class="pln">
    </span><span class="tag">&lt;link</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"</span><span class="pln"> </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"stylesheet"</span><span class="tag">&gt;</span><span class="pln">

    </span><span class="tag">&lt;style&gt;</span><span class="pln">
        body </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">font-family</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Noto Naskh Arabic'</span><span class="pun">,</span><span class="pln"> serif</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="tag">&lt;/style&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"h-screen overflow-hidden bg-gray-100 flex flex-col"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;main</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"min-w-0 flex-1 border-t border-gray-200 flex min-h-0 overflow-hidden"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"min-h-0 flex-1 overflow-y-scroll bg-white bg-white h-full w-full flex"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"p-6 w-full flex flex-col"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-lg font-medium text-gray-900 w-full mb-6"</span><span class="pln"> </span><span class="atn">placeholder</span><span class="pun">=</span><span class="atv">"ملاحظة بدون عنوان"</span><span class="tag">&gt;</span><span class="pln">

                    </span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"w-full mb-6 flex-1 outline-none"</span><span class="pln"> </span><span class="atn">placeholder</span><span class="pun">=</span><span class="atv">"إبدأ الكتابة ..."</span><span class="pln"> </span><span class="atn">autofocus</span><span class="tag">&gt;&lt;/textarea&gt;</span><span class="pln">

                    </span><span class="tag">&lt;div&gt;</span><span class="pln">
                        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm text-gray-900"</span><span class="tag">&gt;</span><span class="pln">حذف الملاحظة</span><span class="tag">&lt;/button&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">

            </span><span class="tag">&lt;aside</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"block flex-shrink-0 order-first h-full relative flex flex-col w-96 border-r border-gray-200 bg-gray-100"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"flex-shrink-0 h-16 bg-white px-6 flex flex-col justify-center"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"flex justify-between space-x-3"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"flex items-baseline"</span><span class="tag">&gt;</span><span class="pln">
                            </span><span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-lg font-bold text-gray-900 mr-3"</span><span class="tag">&gt;</span><span class="pln">
                                ملاحظاتي
                            </span><span class="tag">&lt;/h2&gt;</span><span class="pln">
                            </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm font-medium text-gray-500"</span><span class="tag">&gt;&lt;/p&gt;</span><span class="pln">
                        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm"</span><span class="tag">&gt;</span><span class="pln">ملاحظة جديدة</span><span class="tag">&lt;/button&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">

                </span><span class="tag">&lt;nav</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"min-h-0 flex-1 overflow-y-auto"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"border-b border-gray-200 divide-y divide-gray-200"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"relative bg-white py-5 px-6 hover:bg-gray-50 focus-within:ring-2 focus-within:ring-inset focus-within:ring-blue-600"</span><span class="tag">&gt;</span><span class="pln">
                            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"flex justify-between space-x-3"</span><span class="tag">&gt;</span><span class="pln">
                                </span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"#"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"block focus:outline-none"</span><span class="tag">&gt;</span><span class="pln">
                                    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"absolute inset-0"</span><span class="tag">&gt;&lt;/span&gt;</span><span class="pln">
                                    </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm text-gray-500 truncate"</span><span class="tag">&gt;</span><span class="pln">عُنوان الملاحظة</span><span class="tag">&lt;/p&gt;</span><span class="pln">
                                </span><span class="tag">&lt;/a&gt;</span><span class="pln">

                                </span><span class="tag">&lt;time</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"flex-shrink-0 whitespace-nowrap text-sm text-gray-500"</span><span class="tag">&gt;</span><span class="pln">00:00</span><span class="tag">&lt;/time&gt;</span><span class="pln">
                            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"mt-1"</span><span class="tag">&gt;</span><span class="pln">
                                </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm text-gray-600"</span><span class="tag">&gt;</span><span class="pln">محتوى الملاحظة</span><span class="tag">&lt;/p&gt;</span><span class="pln">
                            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                        </span><span class="tag">&lt;/li&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
                </span><span class="tag">&lt;/nav&gt;</span><span class="pln">
            </span><span class="tag">&lt;/aside&gt;</span><span class="pln">
        </span><span class="tag">&lt;/main&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	بعد فتح الملف على المتصفح ستحصل على الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="JPG" data-fileid="142034" href="https://academy.hsoub.com/uploads/monthly_2024_01/Design.JPG.f6c978bdcf7e98d13e5f9829b9c35420.JPG" rel=""><img alt="design" class="ipsImage ipsImage_thumbnailed" data-fileid="142034" data-unique="llshk058y" src="https://academy.hsoub.com/uploads/monthly_2024_01/Design.thumb.JPG.4d2ce7ae02f64014b479314f7cdb40f8.JPG"> </a>
</p>

<p>
	يتكون القالب من قسمين، قائمة جانبية تحتوي على الملاحظات الموجودة والتي أنشأها المستخدم، زر إنشاء ملاحظة جديدة، عُنصر الملاحظة يتكون من عنوان ومحتوى وتاريخ آخر تعديل، القسم الثاني عبارة عن عرض للملاحظة الفعالة يتكون من حقل إدخال للعُنوان وحقل للمحتوى وفي الأسفل زر حذف الملاحظة.
</p>

<h2 id="-1">
	شرح بناء التطبيق
</h2>

<p>
	سنعتمد في بناء التطبيق على الملاحظة الفعالة بحيث عند فتح الصفحة لأول مرة سيتم مباشرة إنشاء ملاحظة بقيم فارغة وعرضها في قسم العرض ليبدأ المستخدم في كتابة البيانات مباشرة وسيتم حفظ الملاحظة تلقائيًا مع الكتابة، أما إن كان للمستخدم ملاحظات سابقة سنجعل آخر ملاحظة قام المستخدم بتعديلها هي الملاحظة الفعالة وسنقوم بفتحها في قسم العرض لتعديلها، في قسم عرض الملاحظات سنعتمد على حقل آخر تعديل حتى نقوم بترتيب الملاحظات وبعد كل تعديل على الملاحظة الفعالة نُعدل على حقل آخر تعديل الخاص بتلك الملاحظة.
</p>

<h3 id="alpinejsstore">
	تضمين Alpine.js: إنشاء store وإنشاء ملاحظة بدون عنوان
</h3>

<p>
	نبدأ بتضمين Alpine في قسم <code>head</code> عبر <a href="https://academy.hsoub.com/devops/networking/%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%AA%D9%88%D8%B2%D9%8A%D8%B9-%D8%A7%D9%84%D9%85%D8%AD%D8%AA%D9%88%D9%89-content-distribution-networks-r569/" rel="">شبكة CDN</a> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_10" style=""><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">defer</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"</span><span class="tag">&gt;&lt;/script&gt;</span></pre>

<p>
	ثم نقوم بإنشاء مخزن store نُسميه <code>notes</code> دلالة على الملاحظات، لكن قبل إنشائه ننتظر تحميل Alpine ولتحقيق ذلك نستمع إلى حدث <code>alpine:init</code> كما هو موضح في التوثيق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_12" style=""><span class="tag">&lt;script&gt;</span><span class="pln">

    document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'alpine:init'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="com">// سنقوم هنا بكتابة معظم ميزات التطبيق</span><span class="pln">

    </span><span class="pun">})</span><span class="pln">

</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	لإنشاء مخزن store نقوم باستدعاء التابع <code>store</code> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_15" style=""><span class="pln">document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'alpine:init'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="typ">Alpine</span><span class="pun">.</span><span class="pln">store</span><span class="pun">(</span><span class="str">'notes'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">

    </span><span class="pun">})</span><span class="pln">

</span><span class="pun">})</span></pre>

<p>
	بهذا الشكل أنشأنا مخزنًا بالاسم <code>notes</code> وبداخله أنشأنا مصفوفة <code>data</code> سنحفظ بداخلها الملاحظات. الوسيط الثاني للتابع <code>store</code> عبارة عن <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-objects-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r645/" rel="">كائن JavaScript</a>، كما ذكرنا سابقًا أننا سنقوم بإنشاء ملاحظة ونقوم بتفعيلها في حالة لم يكن للمستخدم ملاحظات سابقة، وسنعتمد على التابع <code>init</code> لأن Alpine ستقوم بتنفيذه تلقائيًا، يُمكنك البدء بالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_17" style=""><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

    document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'alpine:init'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="typ">Alpine</span><span class="pun">.</span><span class="pln">store</span><span class="pun">(</span><span class="str">'notes'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

            data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">

            init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Started!'</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">

    </span><span class="pun">})</span><span class="pln">

</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	ستجد عبارة Started في <a href="https://academy.hsoub.com/programming/workflow/%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D9%85%D8%B7%D9%88%D8%B1%D9%8A-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D8%AF%D9%85%D8%AC%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-r1439/" rel="">طرفية المتصفح console</a> بعد فتح الصفحة على المتصفح، الآن سنُعدل التابع <code>init</code> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_19" style=""><span class="pln">init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// في حالة كان للمستخدم ملاحظات لن نقوم بإنشاء ملاحظة</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">length</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// سنقوم بجعل أول ملاحظة في المصفوفة هي الملاحظة الفعالة</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">()</span><span class="pln"> </span><span class="com">// إستدعينا تابع لإنشاء ملاحظة</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

</span><span class="pun">},</span></pre>

<p>
	ثم نُعرف التابع <code>createNote</code> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_21" style=""><span class="pln">createNote</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> id </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">()</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[{</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln"> body</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">},</span><span class="pln"> </span><span class="pun">...</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">]</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	جعلنا للملاحظة مُعرف فريد عبارة فقط عن الوقت الحالي أي وقت إنشاء الملاحظة لجعل الأمر بسيط، واستخدمنا ما يُسمى <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A5%D8%B3%D9%86%D8%A7%D8%AF-%D8%A8%D8%A7%D9%84%D8%AA%D9%81%D9%83%D9%8A%D9%83-destructuring-assignment-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r824/" rel="">بالإسناد عبر التفكيك destructuring assignment</a>.
</p>

<p>
	الآن عند فتح الصفحة سيتم إنشاء ملاحظة بقيم فارغة ومُعرف فريد خاص بها، يُمكنك التأكد من ذلك عبر إنشاء عُنصر <code>span</code> بالشكل التالي في صفحة html:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_23" style=""><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{
    init() {
        console.log(this.$store.notes.data)
    }
}"</span><span class="tag">&gt;&lt;/span&gt;</span></pre>

<p>
	وستجد في الطرفية console أنه تم طباعة كائن <code>data</code> وستجد الملاحظة هناك.
</p>

<h3 id="-2">
	تعريف الملاحظة الفعالة والوصول لها في قسم العرض
</h3>

<p>
	سنقوم في كائن <code>store</code> الخاص بنا بإنشاء خاصية بالاسم <code>currentNoteId</code> دلالة على مُعرف الملاحظة الفعالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_25" style=""><span class="pln">currentNoteId</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span></pre>

<p>
	ثم في التابع <code>createNote</code> نُسند لها قيمة id الملاحظة التي أنشأناها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_27" style=""><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentNoteId </span><span class="pun">=</span><span class="pln"> id</span></pre>

<p>
	نقوم بإنشاء <a href="https://academy.hsoub.com/programming/javascript/%D8%AC%D8%A7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%88%D8%B6%D8%A7%D8%A8%D8%B7%D8%A7%D8%AA%D9%87%D8%A7-getters-and-setters-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r882/" rel="">جالب getter</a> لجلب كائن الملاحظة الفعالة حتى نستطيع استخدامه في المكونات الخاصة بنا بالأعلى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_29" style=""><span class="kwd">get</span><span class="pln"> current</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentNoteId</span><span class="pun">)</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	وهو عبارة عن جالب getter يبحث في المصفوفة <code>data</code> عن الملاحظة عبر المُعرف الخاص بها ويقوم بإرجاع الملاحظة التي يطابق مُعرفها قيمة <code>currentNoteId</code>.
</p>

<p>
	ستُصبح شيفرات JavaScript بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_31" style=""><span class="pln">document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'alpine:init'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="typ">Alpine</span><span class="pun">.</span><span class="pln">store</span><span class="pun">(</span><span class="str">'notes'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">

        currentNoteId</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">

        </span><span class="kwd">get</span><span class="pln"> current</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentNoteId</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">

        init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="com">// في حالة كان للمستخدم ملاحظات لن نقوم بإنشاء ملاحظة</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">length</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="com">// سنقوم بجعل أول ملاحظة في المصفوفة هي الملاحظة الفعالة     </span><span class="pln">
            </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">()</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

        </span><span class="pun">},</span><span class="pln">

        createNote</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">let</span><span class="pln"> id </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">()</span><span class="pln">

            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[{</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln"> body</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">},</span><span class="pln"> </span><span class="pun">...</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">]</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentNoteId </span><span class="pun">=</span><span class="pln"> id
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

</span><span class="pun">})</span></pre>

<p>
	سنقوم الآن بعرض الملاحظة الفعالة في قسم العرض في الصفحة، في العُنصر التالي بالضبط:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_33" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"p-6 w-full flex flex-col"</span><span class="pln"> </span><span class="atn">x-data</span><span class="tag">&gt;</span><span class="pln">

    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">x-text</span><span class="pun">=</span><span class="atv">"$store.notes.current.title"</span><span class="tag">&gt;&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">x-text</span><span class="pun">=</span><span class="atv">"$store.notes.current.body"</span><span class="tag">&gt;&lt;/span&gt;</span><span class="pln">

    </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-lg font-medium text-gray-900 w-full mb-6"</span><span class="pln"> </span><span class="atn">x-model</span><span class="pun">=</span><span class="atv">"$store.notes.current.title"</span><span class="pln"> </span><span class="atn">placeholder</span><span class="pun">=</span><span class="atv">"ملاحظة بدون عنوان"</span><span class="tag">&gt;</span><span class="pln">

    </span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"w-full mb-6 flex-1 outline-none"</span><span class="pln"> </span><span class="atn">x-model</span><span class="pun">=</span><span class="atv">"$store.notes.current.body"</span><span class="pln"> </span><span class="atn">placeholder</span><span class="pun">=</span><span class="atv">"إبدأ الكتابة ..."</span><span class="pln"> </span><span class="atn">autofocus</span><span class="tag">&gt;&lt;/textarea&gt;</span><span class="pln">

    </span><span class="tag">&lt;div&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm text-gray-900"</span><span class="tag">&gt;</span><span class="pln">حذف الملاحظة</span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	لاحظ يجب تحديد الموجه <code>x-data</code> للعُنصر لجعله مكون Alpine وحتى نستطيع استخدام خصائص Alpine بداخله، في كلا حقلي الإدخال استخدمنا الموجه <code>x-model</code> لربط قيمة حقل الإدخال بالخاصية الموافقة في الملاحظة الفعالة واستخدمنا الخاصية <code>store$</code> في Alpine للوصول إلى بيانات الملاحظة الفعالة عبر استدعاء الجالب getter الذي أنشأناه.
</p>

<p>
	عناصر <code>span</code> التي قمنا بإضافتها فقط للتجربة ومعاينة أن القيمة تتغير بالكتابة. جرب الكتابة في الحقول للتأكد من ذلك.
</p>

<h3 id="xfor">
	عرض قائمة الملاحظات باستخدام x-for
</h3>

<p>
	لعرض الملاحظات في القائمة الجانبية سنقوم بوضع بعض البيانات التجريبية في المصفوفة <code>data</code> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_35" style=""><span class="pln">data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">'ملاحظتي الأولى'</span><span class="pun">,</span><span class="pln"> body</span><span class="pun">:</span><span class="pln"> </span><span class="str">'محتوى الملاحظة الأولى'</span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">'ملاحظتي الثانية'</span><span class="pun">,</span><span class="pln"> body</span><span class="pun">:</span><span class="pln"> </span><span class="str">'محتوى الملاحظة الثانية'</span><span class="pun">},</span><span class="pln">
</span><span class="pun">],</span></pre>

<p>
	لكن قبل أن نقوم بعرض الملاحظات سنُحدد مُعرف الملاحظة الفعالة، حيث أننا ذكرنا سابقًا في حالة كان للمستخدم ملاحظات سابقة سنجعل الملاحظة الفعالة هي أول ملاحظة في المصفوفة (حاليًا فقط، سنقوم لاحقًا بترتيب الملاحظات حسب تاريخ آخر تعديل حتى تظهر الملاحظات مرتبة وتكون الملاحظة الفعالة هي آخر ملاحظة قام المستخدم بتعديلها).
</p>

<p>
	سنكتب في التابع <code>init</code> وفي الجزء المخصص لذلك ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_37" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">length</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">setCurrentNoteByIndex</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ونقوم بتعريف التابع <code>setCurrentNoteByIndex</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_39" style=""><span class="pln">setCurrentNoteByIndex</span><span class="pun">(</span><span class="pln">index</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentNoteId </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">[</span><span class="pln">index</span><span class="pun">].</span><span class="pln">id
</span><span class="pun">}</span></pre>

<p>
	وكما تلاحظ أن ما قمنا به هو بالضبط ما شرحته في الأعلى، مررنا الفهرس 0 لتحديد أول ملاحظة في المصفوفة ثم أسندنا مُعرفها للخاصية <code>currentNoteId</code>.
</p>

<p>
	نأتي الآن لعرض الملاحظات في القائمة الجانبية، وبالضبط عُنصر ul في الصفحة، سنستخدم الموجه <code>x-data</code> لجعله مكون Alpine ثم نستخدم <code>x-for</code> للمرور على عناصر المصفوفة <code>data</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_41" style=""><span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"border-b border-gray-200 divide-y divide-gray-200"</span><span class="pln"> </span><span class="atn">x-data</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;template</span><span class="pln"> </span><span class="atn">x-for</span><span class="pun">=</span><span class="atv">"note in $store.notes.data"</span><span class="pln"> :</span><span class="atn">key</span><span class="pun">=</span><span class="atv">"note.id"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"relative bg-white py-5 px-6 hover:bg-gray-50 focus-within:ring-2 focus-within:ring-inset focus-within:ring-blue-600"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"flex justify-between space-x-3"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"#"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"block focus:outline-none"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"absolute inset-0"</span><span class="tag">&gt;&lt;/span&gt;</span><span class="pln">
                    </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm text-gray-500 truncate"</span><span class="pln"> </span><span class="atn">x-text</span><span class="pun">=</span><span class="atv">"note.title || 'ملاحظة بدون عنوان'"</span><span class="tag">&gt;&lt;/p&gt;</span><span class="pln">
                </span><span class="tag">&lt;/a&gt;</span><span class="pln">

                </span><span class="tag">&lt;time</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"flex-shrink-0 whitespace-nowrap text-sm text-gray-500"</span><span class="tag">&gt;</span><span class="pln">00:00</span><span class="tag">&lt;/time&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"mt-1"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm text-gray-600"</span><span class="pln"> </span><span class="atn">x-text</span><span class="pun">=</span><span class="atv">"note.body.substring(0, Math.min(100, note.body.length))"</span><span class="tag">&gt;&lt;/p&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/li&gt;</span><span class="pln">
    </span><span class="tag">&lt;/template&gt;</span><span class="pln">
</span><span class="tag">&lt;/ul&gt;</span></pre>

<p>
	استخدمنا الموجه <code>x-for</code> للمرور على عناصر المصفوفة <code>data</code>، كما هو موضح في التوثيق حتى نستطيع استخدام <code>x-for</code> يجب أن نُعرفها بداخل عُنصر <code>template</code> وهذا العُنصر يجب أن يكون بداخله عُنصر جذر واحد.
</p>

<p>
	أيضًا من المهم جدًا تحديد مفاتيح فريدة لكل تكرار عبر الخاصية <code>key</code> وذلك لأن القائمة ستتحدث فقد يتغير ترتيب الملاحظات أثناء التصفح إذا تغير تاريخ التعديل، وبدون المفاتيح الفريدة ستجد Alpine صعوبة في تحديث <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%B4%D8%AC%D8%B1%D9%8A%D8%A9-%D9%84%D9%80-dom-r646/" rel="">شجرة DOM</a> وقد لا تحصل على نفس النتيجة التي ترغب فيها.
</p>

<p>
	بداخل العناصر استخدمنا الموجه <code>x-text</code> لعرض بيانات الملاحظة، في المُحتوى استخدمنا التابع <code>substring</code> حتى لا يتجاوز عدد المحارف 100 محرف.
</p>

<p>
	ستكون النتيجة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="JPG" data-fileid="142035" href="https://academy.hsoub.com/uploads/monthly_2024_01/listing-notes.JPG.f26e0a24d2290e8411fc31865ca26c4f.JPG" rel=""><img alt="listing notes" class="ipsImage ipsImage_thumbnailed" data-fileid="142035" data-unique="61y1gbyou" src="https://academy.hsoub.com/uploads/monthly_2024_01/listing-notes.thumb.JPG.3fbe039599f8c663c7f6e3ff61dd5cb4.JPG"> </a>
</p>

<p>
	وبطبيعة الحال عند التعديل في قسم العرض ستتحدث بيانات الملاحظة الفعالة وهي الملاحظة الأولى.
</p>

<h3 id="-3">
	إضافة تاريخ آخر تعديل وتغييره بعد كل تعديل على الملاحظة الفعالة
</h3>

<p>
	نقوم بإنشاء تابع جديد بالاسم <code>touchCurrentNote</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_43" style=""><span class="pln">touchCurrentNote</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">current</span><span class="pun">.</span><span class="pln">lastEdited </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">()</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	ثم نستدعي التابع عند إنشاء ملاحظة جديدة حيث سيتم تهيئة حقل lastEdited بالتاريخ الحالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_45" style=""><span class="pln">createNote</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> id </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">()</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[{</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln"> body</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln"> lastEdited</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">},</span><span class="pln"> </span><span class="pun">...</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">]</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentNoteId </span><span class="pun">=</span><span class="pln"> id
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">touchCurrentNote</span><span class="pun">()</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	ثم نقوم أيضًا باستدعائه بعد كل تعديل على الحقول في قسم العرض بالاستماع إلى حدث <code>keyup</code> في حقول الإدخال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_47" style=""><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-lg font-medium text-gray-900 w-full mb-6"</span><span class="pln">
       </span><span class="atn">x-model</span><span class="pun">=</span><span class="atv">"$store.notes.current.title"</span><span class="pln"> </span><span class="atn">placeholder</span><span class="pun">=</span><span class="atv">"ملاحظة بدون عنوان"</span><span class="pln">
       @</span><span class="atn">keyup</span><span class="pun">=</span><span class="atv">"$store.notes.touchCurrentNote()"</span><span class="tag">&gt;</span><span class="pln">

</span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"w-full mb-6 flex-1 outline-none"</span><span class="pln">
          </span><span class="atn">x-model</span><span class="pun">=</span><span class="atv">"$store.notes.current.body"</span><span class="pln">
          @</span><span class="atn">keyup</span><span class="pun">=</span><span class="atv">"$store.notes.touchCurrentNote()"</span><span class="pln">
          </span><span class="atn">placeholder</span><span class="pun">=</span><span class="atv">"إبدأ الكتابة ..."</span><span class="pln"> </span><span class="atn">autofocus</span><span class="tag">&gt;&lt;/textarea&gt;</span></pre>

<p>
	قد تكون الحالة مناسبة لاستعمال المُحدد <code>debounce</code> لفرض بعض التأخير في تنفيذ المعالجة بعد إطلاق الحدث، حتى لا يتم تنفيذ التابع <code>touchCurrentNote</code> بعد كل ضغطة زر لحظيًا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_49" style=""><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-lg font-medium text-gray-900 w-full mb-6"</span><span class="pln">
       </span><span class="atn">x-model</span><span class="pun">=</span><span class="atv">"$store.notes.current.title"</span><span class="pln"> </span><span class="atn">placeholder</span><span class="pun">=</span><span class="atv">"ملاحظة بدون عنوان"</span><span class="pln">
       @</span><span class="atn">keyup</span><span class="pln">.</span><span class="atn">debounce</span><span class="pln">.200</span><span class="atn">ms</span><span class="pun">=</span><span class="atv">"$store.notes.touchCurrentNote()"</span><span class="tag">&gt;</span><span class="pln">

</span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"w-full mb-6 flex-1 outline-none"</span><span class="pln">
          </span><span class="atn">x-model</span><span class="pun">=</span><span class="atv">"$store.notes.current.body"</span><span class="pln">
          @</span><span class="atn">keyup</span><span class="pln">.</span><span class="atn">debounce</span><span class="pln">.200</span><span class="atn">ms</span><span class="pun">=</span><span class="atv">"$store.notes.touchCurrentNote()"</span><span class="pln">
          </span><span class="atn">placeholder</span><span class="pun">=</span><span class="atv">"إبدأ الكتابة ..."</span><span class="pln"> </span><span class="atn">autofocus</span><span class="tag">&gt;&lt;/textarea&gt;</span></pre>

<p>
	سنقوم بإنشاء تابع يقوم بتنسيق تاريخ التعديل بالشكل 18:25 أي الساعة والدقيقة الموافقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_51" style=""><span class="pln">getLastEditedFormatted</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">lastEdited</span><span class="pun">).</span><span class="pln">getHours</span><span class="pun">().</span><span class="pln">toString</span><span class="pun">().</span><span class="pln">padStart</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="str">'0'</span><span class="pun">)}:</span><span class="pln">$</span><span class="pun">{</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">lastEdited</span><span class="pun">).</span><span class="pln">getMinutes</span><span class="pun">().</span><span class="pln">toString</span><span class="pun">().</span><span class="pln">padStart</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="str">'0'</span><span class="pun">)}`</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	يستقبل هذا التابع معامل <code>note</code> لأننا سنستخدمه بداخل الحلقة لعرض التاريخ ونُمرر له الملاحظة التي يتم المرور عليها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_53" style=""><span class="pun">&lt;</span><span class="pln">time </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"flex-shrink-0 whitespace-nowrap text-sm text-gray-500"</span><span class="pln">
      x</span><span class="pun">-</span><span class="pln">text</span><span class="pun">=</span><span class="str">"$store.notes.getLastEditedFormatted(note)"</span><span class="pun">&gt;&lt;/</span><span class="pln">time</span><span class="pun">&gt;</span></pre>

<p>
	يُمكنك تنسيق التاريخ بالشكل الذي تريد، جرب التعديل على الملاحظة الفعالة وسيستجيب عُنصر الوقت للتعديل.
</p>

<h3 id="-4">
	ترتيب الملاحظات حسب تاريخ آخر تعديل
</h3>

<p>
	نقوم بإنشاء جالب getter لجلب قائمة الملاحظات مرتبة بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_55" style=""><span class="kwd">get</span><span class="pln"> orderedByLastEdited</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">((</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> b</span><span class="pun">.</span><span class="pln">lastEdited </span><span class="pun">-</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">lastEdited</span><span class="pun">)</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	وهي طريقة في JavaScript لترتيب مصفوفة.
</p>

<p>
	ثم نستخدم الجالب getter الذي أنشأناه <code>orderedByLastEdited</code> في التابع <code>setCurrentNoteByIndex</code> لتحديد مُعرف الملاحظة الفعالة من المصفوفة المرتبة بدل المصفوفة الأصلية بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_57" style=""><span class="pln">setCurrentNoteByIndex</span><span class="pun">(</span><span class="pln">index</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentNoteId </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">orderedByLastEdited</span><span class="pun">[</span><span class="pln">index</span><span class="pun">].</span><span class="pln">id
</span><span class="pun">},</span></pre>

<p>
	ثم للتجربة نضع البيانات الاختبارية بالشكل التالي:
</p>

<pre class="ipsCode" id="ips_uid_1585_59">data: [
    {id: 1, title: 'ملاحظتي الأولى', body: 'محتوى الملاحظة الأولى', lastEdited: 1},
    {id: 2, title: 'ملاحظتي الثانية', body: 'محتوى الملاحظة الثانية', lastEdited: 2},
],
</pre>

<p>
	سنقوم أيضًا باستخدام المصفوفة المرتبة في الحلقة بدل المصفوفة الأصلية باستدعاء الجالب getter الذي أنشأناه <code>orderedByLastEdited</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_61" style=""><span class="pun">&lt;</span><span class="pln">template x</span><span class="pun">-</span><span class="kwd">for</span><span class="pun">=</span><span class="str">"note in $store.notes.orderedByLastEdited"</span><span class="pln"> </span><span class="pun">:</span><span class="pln">key</span><span class="pun">=</span><span class="str">"note.id"</span><span class="pun">&gt;</span></pre>

<p>
	بهذا الشكل من المفترض أن الملاحظة الثانية ستظهر أولاً في القائمة.
</p>

<h3 id="-5">
	تبديل الملاحظة الفعالة من القائمة وتفعيل زر إنشاء ملاحظة جديدة
</h3>

<p>
	لتبديل الملاحظة الفعالة نستمع إلى حدث النقر على عُنصر الملاحظة ونُغير <code>currentNoteId</code> إلى مُعرف الملاحظة التي تم الضغط عليها <a href="https://academy.hsoub.com/programming/javascript/%D8%AD%D9%84%D9%82%D8%A7%D8%AA-for-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D8%A8%D8%A8%D8%B3%D8%A7%D8%B7%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r624/" rel="">بالحلقة <code>for</code></a>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_63" style=""><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"#"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"block focus:outline-none"</span><span class="pln">
    @</span><span class="atn">click</span><span class="pln">.</span><span class="atn">prevent</span><span class="pun">=</span><span class="atv">"$store.notes.currentNoteId = note.id"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"absolute inset-0"</span><span class="tag">&gt;&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm text-gray-500 truncate"</span><span class="pln">
       </span><span class="atn">x-text</span><span class="pun">=</span><span class="atv">"note.title || 'ملاحظة بدون عنوان'"</span><span class="tag">&gt;&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/a&gt;</span></pre>

<p>
	الآن إذا جربت، بعد الضغط على أي ملاحظة سيتم تحديدها وعرضها في قسم العرض للتعديل عليها، بمجرد تعديل العنوان أو المحتوى سيتم دفعها لتُصبح في أعلى القائمة وهذا لأن تاريخ التعديل تغير وبالتالي الترتيب سيتغير ويتم تحديث شجرة DOM تلقائيًا.
</p>

<p>
	يُمكنك الآن إفراغ مصفوفة الملاحظات من البيانات الاختبارية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_66" style=""><span class="pln">data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span></pre>

<p>
	ثم نقوم بتفعيل زر إضافة ملاحظة جديدة، لقد قمنا بالفعل بكتابة منطق إضافة ملاحظة سنستمع إلى حدث النقر على الزر ونستدعي التابع <code>createNote</code>:
</p>

<p>
	نقوم أولا بإضافة الموجه <code>x-data</code> لتحديد العُنصر كمُكون Alpine ثم نستخدم <code>click@</code> في الزر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_68" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"flex-shrink-0 h-16 bg-white px-6 flex flex-col justify-center"</span><span class="pln"> </span><span class="atn">x-data</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"flex justify-between space-x-3"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"flex items-baseline"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-lg font-bold text-gray-900 mr-3"</span><span class="tag">&gt;</span><span class="pln">
                ملاحظاتي
            </span><span class="tag">&lt;/h2&gt;</span><span class="pln">
            </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm font-medium text-gray-500"</span><span class="tag">&gt;&lt;/p&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm"</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"$store.notes.createNote()"</span><span class="tag">&gt;</span><span class="pln">ملاحظة جديدة</span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	سنقوم بإضافة عداد بجانب الكلمة ملاحظاتي لعرض عدد الملاحظات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_70" style=""><span class="pun">&lt;</span><span class="pln">h2 </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"text-lg font-bold text-gray-900 mr-3"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">ملاحظاتي</span><span class="pln">
    </span><span class="pun">(&lt;</span><span class="pln">span x</span><span class="pun">-</span><span class="pln">text</span><span class="pun">=</span><span class="str">"$store.notes.data.length"</span><span class="pun">&gt;&lt;/</span><span class="pln">span</span><span class="pun">&gt;)</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span></pre>

<h3 id="-6">
	مزامنة الملاحظات مع الذاكرة المحلية بالمتصفح
</h3>

<p>
	سنقوم بإنشاء تابع بالاسم <code>persistNotes</code> يقوم بحفظ الملاحظات في الذاكرة المحلية بالشكل التالي:
</p>

<pre class="ipsCode">persistNotes() {
    localStorage.setItem('notes', JSON.stringify(this.data))
},
</pre>

<p>
	سنستدعي هذا التابع عند التعديل على الملاحظة الفعالة بجانب <code>touchCurrentNote</code>، يمكنك استدعاء التابعين مباشرةً في العنصر لكننا سنُنشئ تابع بالاسم <code>currentNoteUpdated</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_72" style=""><span class="pln">currentNoteUpdated</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">touchCurrentNote</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">persistNotes</span><span class="pun">()</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	لاحظ أننا استدعينا كلا التابعين الآن عند التعديل في الحقول وعند الاستماع إلى حدث <code>keyup@</code> سنستدعي هذا التابع <code>currentNoteUpdated</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_74" style=""><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-lg font-medium text-gray-900 w-full mb-6"</span><span class="pln">
       </span><span class="atn">x-model</span><span class="pun">=</span><span class="atv">"$store.notes.current.title"</span><span class="pln"> </span><span class="atn">placeholder</span><span class="pun">=</span><span class="atv">"ملاحظة بدون عنوان"</span><span class="pln">
       @</span><span class="atn">keyup</span><span class="pln">.</span><span class="atn">debounce</span><span class="pln">.200</span><span class="atn">ms</span><span class="pun">=</span><span class="atv">"$store.notes.currentNoteUpdated()"</span><span class="tag">&gt;</span><span class="pln">

</span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"w-full mb-6 flex-1 outline-none"</span><span class="pln">
          </span><span class="atn">x-model</span><span class="pun">=</span><span class="atv">"$store.notes.current.body"</span><span class="pln">
          @</span><span class="atn">keyup</span><span class="pln">.</span><span class="atn">debounce</span><span class="pln">.200</span><span class="atn">ms</span><span class="pun">=</span><span class="atv">"$store.notes.currentNoteUpdated()"</span><span class="pln">
          </span><span class="atn">placeholder</span><span class="pun">=</span><span class="atv">"إبدأ الكتابة ..."</span><span class="pln"> </span><span class="atn">autofocus</span><span class="tag">&gt;&lt;/textarea&gt;</span></pre>

<p>
	نحتاج أيضاً إلى استدعاء التابع <code>persistNotes</code> بداخل التابع <code>createNote</code> حتى يتم حفظ الحالة بعد إنشاء ملاحظة جديدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_76" style=""><span class="pln">createNote</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> id </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">()</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[{</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln"> body</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln"> lastEdited</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">},</span><span class="pln"> </span><span class="pun">...</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">]</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentNoteId </span><span class="pun">=</span><span class="pln"> id
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">touchCurrentNote</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">persistNotes</span><span class="pun">()</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	الآن سيتم حفظ الملاحظات لكن نحتاج إلى تهيئة المصفوفة data فإن كانت هناك بيانات في الذاكرة المحلية قمنا بجلبها وإلا نهيئ data بمصفوفة فارغة:
</p>

<pre class="ipsCode">data: JSON.parse(localStorage.getItem('notes')) || [],
</pre>

<p>
	يُمكنك الآن إنشاء ملاحظاتك والتعديل عليها وعند تحديث الصفحة ستبقى موجودة.
</p>

<h3 id="-7">
	تفعيل زر الحذف
</h3>

<p>
	آخر شيء سنقوم به هو تفعيل زر حذف ملاحظة، لتحقيق ذلك سنقوم بإنشاء تابع بالاسم <code>deleteNote</code> يستقبل مُعرف الملاحظة التي نريد حذفها، بداخلها نتحقق: إذا كانت الملاحظة التي يريد المستخدم حذفها هي آخر ملاحظة في القائمة فنقوم في هذه الحالة بإنشاء ملاحظة جديدة قبل حذف الملاحظة الأخيرة حتى تبقى دائماً ملاحظة فعالة في التطبيق، نحذف الملاحظة من المصفوفة data، ثم نستدعي <code>persistNotes</code> لحفظ الحالة وأخيراً نستدعي <code>setCurrentNoteByIndex</code> لإعادة تحديد الملاحظة الفعالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1585_79" style=""><span class="pln">deleteNote</span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">length </span><span class="pun">===</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">persistNotes</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">setCurrentNoteByIndex</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نستدعي التابع الذي أنشأناه في زر الحذف عبر الاستماع إلى حدث الضغط على الزر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1585_81" style=""><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-sm text-gray-900"</span><span class="pln">
        @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"if (window.confirm('تأكيد الحذف؟')) {$store.notes.deleteNote($store.notes.currentNoteId)}"</span><span class="pln">
</span><span class="tag">&gt;</span><span class="pln">حذف الملاحظة</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	قمنا بعرض رسالة تأكيد للمستخدم حتى يؤكد الحذف، واستدعينا التابع <code>deleteNote</code>.
</p>

<p>
	إليك الملف النهائي الخاص بالمشروع <a class="ipsAttachLink" data-fileext="zip" data-fileid="142038" href="https://academy.hsoub.com/applications/core/interface/file/attachment.php?id=142038&amp;key=c8c43fe2a1f6a089488314dfcd35ff6e" rel="">project-20240112T115021Z-001.zip</a>
</p>

<h2 id="-8">
	خاتمة
</h2>

<p>
	في نهاية رحلتنا في برمجة تطبيق ملاحظات بسيط باستخدام إطار العمل Alpine.js، نجد أن هذا الإطار يعد أداة قوية وسهلة الاستخدام لتحقيق تجارب مستخدم ديناميكية على الويب. مكنتنا ميزات Alpine.js من بناء تطبيق ملاحظات بسيط بكود نظيف وقليل التعقيد، مع القدرة على التفاعل المباشر مع العناصر والبيانات.
</p>

<p>
	تمثل قدرة Alpine.js على إدارة الحالة وتفعيل السمات بشكل مبسّط جزءًا أساسيًا من تجربة التطوير. يظهر الكود القصير والسلس كيف يمكن للمطورين بسهولة إضافة وظائف جديدة وتحسين التطبيق دون الحاجة إلى التورط في تفاصيل معقدة.
</p>

<p>
	يعتبر تصميم تطبيق الملاحظات باستخدام Alpine.js فعّالًا لفهم كيف يمكن دمج هذا الإطار في مشاريع الويب الحقيقية. إن تنظيم الكود وتسهيل عمليات الربط بين الواجهة الأمامية والواجهة الخلفية يعزز الإنتاجية ويوفر تجربة تطوير فعّالة.
</p>

<p>
	ختامًا، يظهر أن Alpine.js يعد خيارًا ممتازًا للمطورين الذين يسعون إلى تطوير تطبيقات ويب صغيرة إلى متوسطة الحجم بطريقة سهلة وفعّالة. يمكن لهذا الإطار أن يكون أحد الأدوات المفضلة لتحقيق تفاعل المستخدم بشكل سلس وسهل التكامل.
</p>

<h2 id="-9">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/javascript/" rel="">تعلم لغة جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">الدليل السريع إلى لغة البرمجة جافاسكريبت JavaScript</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/%D8%A3%D8%B7%D8%B1-%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-r784/" rel="">أطر عمل الويب من طرف الخادم</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2230</guid><pubDate>Sat, 27 Jan 2024 12:09:03 +0000</pubDate></item><item><title>&#x623;&#x645;&#x62B;&#x644;&#x629; &#x639;&#x646; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Alpine.js</title><link>https://academy.hsoub.com/programming/javascript/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%86-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-alpinejs-r2229/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_01/----Alpine.js-d1-2.png.76f0fbe255832b5ce4390405c1977796.png" /></p>
<p>
	بعد أن تعرفنا في <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-alpinejs-r2214/" rel="">المقال السابق</a> على إطار العمل Alpine.js وأنشأنا نموذج مُصغر للإطار من الصفر بهدف التعلم وفهم آلية عمل هذا الإطار، سنقوم في هذا المقال بإنشاء بعض الأمثلة البسيطة باستخدام Alpine.js وسنُغطي مجموعة من المواضيع المهمة في الإطار كإنشاء المكونات، التعامل مع الأحداث، عرض البيانات وإنشاء رسومات متحركة.
</p>
<iframe allowfullscreen="" class="ipsEmbed_finishedLoading" data-controller="core.front.core.autosizeiframe" data-embedauthorid="3889" data-embedcontent="" data-embedid="embed9612071517" src="https://academy.hsoub.com/files/27-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA/?do=embed" style="overflow: hidden; height: 470px; max-width: 500px; margin:auto;"></iframe>

<h2 id="modal">
	إنشاء نافذة منبثقة Modal
</h2>

<p>
	هذا المثال لإنشاء نافذة منبثقة عبر Alpine.js، نقوم أولًا بإنشاء هيكلية HTML:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_7" style=""><span class="dec">&lt;!doctype html&gt;</span><span class="pln">
</span><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"ar"</span><span class="pln"> </span><span class="atn">dir</span><span class="pun">=</span><span class="atv">"rtl"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"UTF-8"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"viewport"</span><span class="pln">
          </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">http-equiv</span><span class="pun">=</span><span class="atv">"X-UA-Compatible"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"ie=edge"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">مثال لنافذة منبثقة</span><span class="tag">&lt;/title&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"modal-wrapper"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"modal"</span><span class="tag">&gt;</span><span class="pln">
        محتوى النافذة المنبثقة
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	سنضيف بعض <a href="https://academy.hsoub.com/programming/html/html-%D9%88-css-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%AA%D9%86%D8%B3%D9%8A%D9%82%D8%A7%D8%AA-css-r272/" rel="">تنسيقات CSS</a> لتظهر النافذة بشكل جيد، في عنصر <code>head</code> نضيف وسم <code>style</code> ونضع به التنسيقات التالية:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_7133_9" style=""><span class="pun">&lt;</span><span class="pln">style</span><span class="pun">&gt;</span><span class="pln">
    body </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="pun">.</span><span class="pln">modal-wrapper </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100%</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100%</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">background-color</span><span class="pun">:</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">.5</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">align-items</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">justify-content</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="pun">.</span><span class="pln">modal </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">background-color</span><span class="pun">:</span><span class="pln"> </span><span class="lit">#fff</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30%</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">box-shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">#333</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">border-radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">style</span><span class="pun">&gt;</span></pre>

<p>
	وسيكون مظهر النافذة بعد فتح <a href="https://academy.hsoub.com/programming/html/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-html-r1702/" rel="">صفحة HTML</a> بالشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="JPG" data-fileid="142030" href="https://academy.hsoub.com/uploads/monthly_2024_01/modal-show.JPG.956e49ece1d16eb5387e2b880fb99613.JPG" rel=""><img alt="modal show" class="ipsImage ipsImage_thumbnailed" data-fileid="142030" data-unique="h4mzkvrfz" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2024_01/modal-show.thumb.JPG.547e3a89bb2381a134d9acb4676913f6.JPG"> </a>
</p>

<p>
	نريد التحكم الآن في إخفاء هذه النافذة، بحيث عند الضغط بزر الفأرة خارج حاوية النافذة البيضاء أو عند الضغط على زر الهروب escape تختفي النافذة، نقوم أولاً بتضمين إطار العمل Alpine.js عبر <a href="https://academy.hsoub.com/apps/web/wordpress/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%AA%D9%88%D8%B2%D9%8A%D8%B9-%D8%A7%D9%84%D9%85%D8%AD%D8%AA%D9%88%D9%89-cdn-%D9%84%D8%AA%D8%AD%D8%B3%D9%8A%D9%86-%D8%A3%D8%AF%D8%A7%D8%A1-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%88%D9%88%D8%B1%D8%AF%D8%A8%D8%B1%D9%8A%D8%B3-r299/" rel="">شبكة CDN</a> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_11" style=""><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://unpkg.com/alpinejs"</span><span class="pln"> </span><span class="atn">defer</span><span class="tag">&gt;&lt;/script&gt;</span></pre>

<p>
	وكما تعلمنا سابقاً نستعمل أولاً الموجه <code>x-data</code> لنستطيع استعمال كافة ما تتيحه Alpine داخل المكون، بما أننا نريد التحكم في إظهار أو إخفاء النافذة، سنعرف خاصية بالاسم <code>open</code>، بحيث إذا كانت <code>true</code> فذلك يعني أن النافذة مفتوحة وإذا كانت <code>false</code> فإن النافذة مُغلقة، ونتحكم في ذلك عبر المُوجه <code>x-show</code> ونمرر له اسم الخاصية <code>open</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_13" style=""><span class="tag">&lt;div</span><span class="pln">
        </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"modal-wrapper"</span><span class="pln">
        </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{ open: true }"</span><span class="pln">
        </span><span class="atn">x-show</span><span class="pun">=</span><span class="atv">"open"</span><span class="pln">
</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"modal"</span><span class="tag">&gt;</span><span class="pln">
        محتوى النافذة المنبثقة
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	سترى أن النافذة مفتوحة افتراضيًا عند فتح الصفحة، يُمكنك تجربة تغيير القيمة الابتدائية من <code>true</code> إلى <code>false</code> وسترى أنها تستجيب لذلك.
</p>

<p>
	بما أننا نرغب عند النقر خارج الحاوية البيضاء بإخفاء النافذة فإننا سنستخدم المُوجه <code>x-on</code> للاستماع الى حدث النقر، لكني افضل استخدام الطريقة المختصرة @ ثم اسم الحدث أي <code>click@</code> يُمكنك استخدام أي طريقة تريد سواء المختصرة <code>click@</code> أو <code>x-on:click</code> ونحدد المُعدل <code>outside</code> للدلالة على أن الإستماع سيكون عند النقر خارج العُنصر المحدد:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_15" style=""><span class="tag">&lt;div</span><span class="pln">
        </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"modal-wrapper"</span><span class="pln">
        </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{ open: true }"</span><span class="pln">
        </span><span class="atn">x-show</span><span class="pun">=</span><span class="atv">"open"</span><span class="pln">
</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"modal"</span><span class="pln"> @</span><span class="atn">click</span><span class="pln">.</span><span class="atn">outside</span><span class="pun">=</span><span class="atv">"open = false"</span><span class="tag">&gt;</span><span class="pln">
        محتوى النافذة المنبثقة
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	الآن عند فتح الصفحة ستظهر النافذة وعند النقر خارج الحاوية البيضاء ستختفي النافذة المنبثقة، وهذا لأننا حددنا أنه عندما يتم النقر قم بتغيير قيمة <code>open</code> إلى <code>false</code> وبالتالي يتم تحديث <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%B4%D8%AC%D8%B1%D8%A9-dom-%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1104/" rel="">شجرة DOM</a> وتختفي النافذة المنبثقة.
</p>

<p>
	بخصوص الضغط على زر الهروب escape لإخفاء النافذة المنبثقة سنستخدم حدث <code>keyup</code> للإستماع إلى حدث الضغط على الزر المطلوب ثم نمرر المعدل <code>window</code> لتحديد أن الإستماع سيحدث على مستوى الصفحة بشكل كامل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_17" style=""><span class="tag">&lt;div</span><span class="pln">
        </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"modal-wrapper"</span><span class="pln">
        </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{ open: true }"</span><span class="pln">
        </span><span class="atn">x-show</span><span class="pun">=</span><span class="atv">"open"</span><span class="pln">
        @</span><span class="atn">keyup</span><span class="pln">.</span><span class="atn">escape</span><span class="pln">.</span><span class="atn">window</span><span class="pun">=</span><span class="atv">"open = false"</span><span class="pln">
</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"modal"</span><span class="pln"> @</span><span class="atn">click</span><span class="pln">.</span><span class="atn">outside</span><span class="pun">=</span><span class="atv">"open = false"</span><span class="tag">&gt;</span><span class="pln">
        محتوى النافذة المنبثقة
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	لحد الآن لا توجد طريقة لإظهار النافذة المنبثقة سوى بتحديث الصفحة، سنتيح ذلك الآن، نقوم بتغيير قيمة <code>open</code> الافتراضية إلى <code>false</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_19" style=""><span class="pln">x-data="{ open: false }"</span></pre>

<p>
	ثم نضيف خارج المكون زر لفتح النافذة المنبثقة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_21" style=""><span class="tag">&lt;button&gt;</span><span class="pln">فتح النافذة المنبثقة</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	بما أن الزر موجود خارج المكون فهو لا يعلم أي شيء عن بيانات ذلك المكون ولا يستطيع الوصول لها وبالتالي لا يستطيع التحكم فيها، سنُعرف بداخله الخاصية <code>x-data</code> حتى نتمكن من استعمال Alpine بداخله، ثم نستخدم الخاصية <code>dispatch$</code> التي تُتيحها Alpine لإطلاق حدث خاص:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_23" style=""><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">x-data</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"$dispatch('open-modal')"</span><span class="tag">&gt;</span><span class="pln">فتح النافذة المنبثقة</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	يمكن تسمية الحدث بأي اسم لقد أسميته <code>open-modal</code>، ثم في المكون الأساسي يمكن الاستماع إلى الحدث الخاص الذي تم إطلاقه بنفس الطريقة التي نستخدمها في الإستماع إلى الأحداث العادية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_25" style=""><span class="pln">@open-modal.window="open = true"</span></pre>

<p>
	بحيث تُصبح هيكلية HTML بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_27" style=""><span class="tag">&lt;div</span><span class="pln">
        </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"modal-wrapper"</span><span class="pln">
        </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{ open: false }"</span><span class="pln">
        </span><span class="atn">x-show</span><span class="pun">=</span><span class="atv">"open"</span><span class="pln">
        @</span><span class="atn">keyup</span><span class="pln">.</span><span class="atn">esc</span><span class="pln">.</span><span class="atn">window</span><span class="pun">=</span><span class="atv">"open = false"</span><span class="pln">
        @</span><span class="atn">open-modal</span><span class="pln">.</span><span class="atn">window</span><span class="pun">=</span><span class="atv">"open = true"</span><span class="pln">
    </span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"modal"</span><span class="pln"> @</span><span class="atn">click</span><span class="pln">.</span><span class="atn">outside</span><span class="pun">=</span><span class="atv">"open = false"</span><span class="tag">&gt;</span><span class="pln">
        محتوى النافذة المنبثقة
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">x-data</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"$dispatch('open-modal')"</span><span class="tag">&gt;</span><span class="pln">فتح النافذة المنبثقة</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	بهذا الشكل نكون قد أنشأنا مثال بسيط عن مكون نافذة منبثقة، وتحكمنا في إظهاره وإخفائه.
</p>

<h2 id="markdownparser">
	إنشاء مفسر لصيغة ماركداون Markdown Parser
</h2>

<p>
	إن لم تكن لديك معرفة مسبقة بصيغة ماركداون فأدعوك للإطلاع على المقالتين: <a href="https://academy.hsoub.com/apps/productivity/%D9%85%D8%A7%D8%B1%D9%83%D8%AF%D8%A7%D9%88%D9%86-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86-r289/" rel="">ماركداون للمبرمجين</a> و <a href="https://academy.hsoub.com/apps/productivity/%D9%83%D9%8A%D9%81-%D8%AA%D9%83%D8%AA%D8%A8-%D8%A8%D8%B5%D9%8A%D8%BA%D8%A9-%D9%85%D8%A7%D8%B1%D9%83%D8%AF%D8%A7%D9%88%D9%86-%D8%A8%D8%A8%D8%B3%D8%A7%D8%B7%D8%A9-r290/" rel="">كيف تكتب بصيغة ماركداون ببساطة</a>، لن نقوم بإنشاء مفسر من الصفر وإنما سنستخدم مكتبة <a href="https://www.npmjs.com/package/marked" rel="external nofollow" target="_blank">marked</a> وسيكون مثالنا في إنشاء حقل إدخال نكتب من خلاله بصيغة ماركداون ثم نضغط على زر ليقوم بتفسير تلك الصيغة ويعرض لنا ما يوافقها:
</p>

<p>
	نبدأ بإنشاء هيكلية HTML:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_29" style=""><span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"ar"</span><span class="pln"> </span><span class="atn">dir</span><span class="pun">=</span><span class="atv">"rtl"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"UTF-8"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"viewport"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"width=device-width, initial-scale=1.0"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">مفسر صيغة ماركداون</span><span class="tag">&lt;/title&gt;</span><span class="pln">
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://unpkg.com/alpinejs"</span><span class="pln"> </span><span class="atn">defer</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://cdn.jsdelivr.net/npm/marked/marked.min.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{
    body: '',
    markdown: ''
}"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div&gt;</span><span class="pln">
        </span><span class="tag">&lt;div&gt;</span><span class="pln">
            </span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">cols</span><span class="pun">=</span><span class="atv">"50"</span><span class="pln"> </span><span class="atn">rows</span><span class="pun">=</span><span class="atv">"10"</span><span class="tag">&gt;&lt;/textarea&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">

        </span><span class="tag">&lt;button&gt;</span><span class="pln">عرض</span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;div&gt;</span><span class="pln">
        المحتوى
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	المحتوى بسيط فقط قمنا بتضمين إطار Alpine.js ثم حزمة marked التي ستساعدنا في عملية التفسير، عرفنا مكون يحتوي على خاصيتين body هو المحتوى الذي سيتم كتابته عبر حقل الإدخال، و markdown هو نتيجة التفسير والذي سيكون عبارة عن html.
</p>

<p>
	نقوم بربط الخاصية body مع حقل الإدخال باستخدام المُوجه <code>x-model</code> بحيث عند الكتابة في حقل الإدخال تتغير القيمة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_31" style=""><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">cols</span><span class="pun">=</span><span class="atv">"50"</span><span class="pln"> </span><span class="atn">rows</span><span class="pun">=</span><span class="atv">"10"</span><span class="pln"> </span><span class="atn">x-model</span><span class="pun">=</span><span class="atv">"body"</span><span class="tag">&gt;&lt;/textarea&gt;</span></pre>

<p>
	نستمع الى حدث النقر ونقوم بتفسير القيمة المدخلة في حقل الإدخال ونسندها إلى الخاصية <code>markdown</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_33" style=""><span class="tag">&lt;button</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"markdown = marked.parse(body)"</span><span class="tag">&gt;</span><span class="pln">عرض</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	نقوم بعرض المحتوى باستخدام المُوجه <code>x-html</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_35" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">x-html</span><span class="pun">=</span><span class="atv">"markdown"</span><span class="tag">&gt;&lt;/div&gt;</span></pre>

<p>
	الآن إذا أدخلت محتوى بصيغة ماركداون في حقل الإدخال وضغطت على عرض سيتم عرضه بشكل مُفسر
</p>

<p>
	جرب إدخال التالي في حقل الإدخال:
</p>

<pre class="ipsCode"># عنوان أول
## عنوان ثاني
### عنوان ثالث
#### عنوان رابع

**نص ثخين**
*نص مائل*
~~نص مشطوب~~

&gt; هذا مثال على اقتباس

مثال عن رابط: [أكاديمية حسوب](https://academy.hsoub.com/)

قائمة عناصر:
* عنصر
* عنصر آخر
* عنصر آخر

قائمة مرتبة:
1. عنصر أول
2. عنصر ثانٍ
3. عنصر ثالث.
</pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="142028" href="https://academy.hsoub.com/uploads/monthly_2024_01/markdown-parser-content.png.c43e1111545ceb9ff5b5549158f3a0b8.png" rel=""><img alt="markdown parser content" class="ipsImage ipsImage_thumbnailed" data-fileid="142028" data-unique="b48b23t6s" style="width: 697px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2024_01/markdown-parser-content.thumb.png.e966f66a3f29c818e676b049f98ca1b0.png"> </a>
</p>

<p>
	بعد الضغط على زر عرض ستحصل على النتيجة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="142029" href="https://academy.hsoub.com/uploads/monthly_2024_01/markdown-parser-result.png.791753a4227067cf0242faa5699f9b74.png" rel=""><img alt="markdown parser result" class="ipsImage ipsImage_thumbnailed" data-fileid="142029" data-unique="2656tw7tk" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2024_01/markdown-parser-result.thumb.png.68bd01bca1d462383b9d72c64f52b265.png"> </a>
</p>

<p>
	يُمكن في الكائن <code>x-data</code> إنشاء توابع وغير ذلك مما يمكن استعماله في كائنات جافاسكربت، سنقوم بإنشاء تابع يقوم بعملية التفسير ونستدعيه عند الاستماع إلى حدث الضغط حيث يصبح المكون بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_37" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{
    body: '',
    markdown: '',
    parseMarkdown() {
        this.markdown = marked.parse(this.body)
    }
}"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div&gt;</span><span class="pln">
        </span><span class="tag">&lt;div&gt;</span><span class="pln">
            </span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">cols</span><span class="pun">=</span><span class="atv">"50"</span><span class="pln"> </span><span class="atn">rows</span><span class="pun">=</span><span class="atv">"10"</span><span class="pln"> </span><span class="atn">x-model</span><span class="pun">=</span><span class="atv">"body"</span><span class="tag">&gt;&lt;/textarea&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">

        </span><span class="tag">&lt;button</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"parseMarkdown"</span><span class="tag">&gt;</span><span class="pln">عرض</span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">x-html</span><span class="pun">=</span><span class="atv">"markdown"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<h2 id="circularprogressbar">
	إنشاء شريط تقدم دائري متحرك circular progress bar
</h2>

<p>
	سنقوم أولا بإنشاء هيكلية عناصر HTML واستخدام CSS لتنسيق شريط التقدم:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_39" style=""><span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"en"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"UTF-8"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"viewport"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"width=device-width, initial-scale=1.0"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">Animated circular progress bar</span><span class="tag">&lt;/title&gt;</span><span class="pln">
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://unpkg.com/alpinejs"</span><span class="pln"> </span><span class="atn">defer</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">

    </span><span class="tag">&lt;style&gt;</span><span class="pln">
        body </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">box </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">flex-direction</span><span class="pun">:</span><span class="pln"> column</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">align-items</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">justify-content</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100%</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100%</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">progress </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">250px</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">250px</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">border-radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50%</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">background</span><span class="pun">:</span><span class="pln"> conic-gradient</span><span class="pun">(</span><span class="pln">slategray </span><span class="lit">306deg</span><span class="pun">,</span><span class="pln"> </span><span class="lit">#ddd</span><span class="pln"> </span><span class="lit">0deg</span><span class="pun">);</span><span class="pln">
            </span><span class="kwd">display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">align-items</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">justify-content</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="pun">.</span><span class="kwd">progress</span><span class="pun">::</span><span class="pln">before</span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">content</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">210px</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">210px</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">border-radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50%</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">background-color</span><span class="pun">:</span><span class="pln"> </span><span class="lit">#fff</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="pun">.</span><span class="pln">progress-inner</span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">font-size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40px</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">font-weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">600</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">color</span><span class="pun">:</span><span class="pln"> slategray</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">text</span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">font-size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30px</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">font-weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">500</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">color</span><span class="pun">:</span><span class="pln"> </span><span class="lit">#606060</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">margin-top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="tag">&lt;/style&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"box"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"progress"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"progress-inner"</span><span class="tag">&gt;</span><span class="pln">85%</span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text"</span><span class="tag">&gt;</span><span class="pln">Alpine Js</span><span class="tag">&lt;/span&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	سيكون المظهر بالشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2024_01/animated-circular-progress-bar.JPG.a64b1570c48dd1a5c5c744e06de35bed.JPG" data-fileid="142033" data-fileext="JPG" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="142033" data-ratio="54.89" data-unique="ln7o8w53g" width="900" alt="animated-circular-progress-bar.JPG" src="https://academy.hsoub.com/uploads/monthly_2024_01/animated-circular-progress-bar.thumb.JPG.519e60c3b2479b2fe176ae715b2b35cd.JPG"></a>
</p>

<p>
	يُمكنك استخدام أي تنسيقات ترغب بها، ما يهم أننا سنستهدف الخاصية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_41" style=""><span class="pln">background: conic-gradient(slategray 306deg, #ddd 0deg);</span></pre>

<p>
	القيمة 306deg بالضبط، حيث أننا سنحصل عليها من ضرب نسبة التقدم في 3.6، أي لما تكون النسبة 100% فإن القيمة تكون 360 درجة فهي عبارة عن قيس زاوية. وعندما تكون نسبة التقدم 50% تكون قيمة الزاوية 180 درجة وهي حاصل ضرب 50 في 3.6 لأننا سنبدأ التحريك من 0 إلى غاية القيمة النهائية.
</p>

<p>
	لذلك سنجعل القيمة الابتدائية 0 بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_43" style=""><span class="pln">background: conic-gradient(slategray 0deg, #ddd 0deg);</span></pre>

<p>
	ثم نأتي لنبني المكون عبر Alpine.js ونبدأ بتعريف <code>x-data</code> في العُنصر progress، بحيث نحدد الخصائص التالية: currentValue وسنعتمد عليها في زيادة قيمة التقدم وتكون مُهيأة بالقيمة 0، endValue وهي القيمة الأعظمية للتقدم، speed خاصية زمنية سنعتمد عليها في تسريع التحريك.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_45" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"box"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"progress"</span><span class="pln">
        </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{
            currentValue: 0,
            endValue: 85,
            speed: 20, // ms
        }"</span><span class="pln">
    </span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"progress-inner"</span><span class="pln"> </span><span class="atn">x-text</span><span class="pun">=</span><span class="atv">"currentValue + '%'"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text"</span><span class="tag">&gt;</span><span class="pln">Alpine Js</span><span class="tag">&lt;/span&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	ستلاحظ أننا حددنا <code>x-text</code> للعنصر progress-inner حتى تكون القيمة ديناميكية وتتحدث كلما تغيرت قيمة currentValue.
</p>

<p>
	الآن سنقوم بتعريف تابع بالاسم init داخل <code>x-data</code> هذا التابع سيتم تنفيذه مباشرةً بعد تهيئة المكون يمكنك تجربة التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_47" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"progress"</span><span class="pln">
    </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{
        currentValue: 0,
        endValue: 85,
        speed: 20, // ms

        init() {
            console.log('Initialized')
        }
    }"</span><span class="pln">
</span><span class="tag">&gt;</span></pre>

<p>
	ستجد أنه يتم طباعة العبارة Initialized في <a href="https://academy.hsoub.com/programming/workflow/%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D9%85%D8%B7%D9%88%D8%B1%D9%8A-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D8%AF%D9%85%D8%AC%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-r1439/" rel="">الطرفية console</a> عند تحديث الصفحة، نحن لم نستدعي التابع، هذا لأن Alpine.js تقوم بذلك تلقائيًا، يُمكن أيضًا استخدام الموجه <code>x-init</code> لنفس الغرض.
</p>

<p>
	سنقوم بداخل التابع <code>init</code> استخدام <code>setInterval</code> لتنفيذ دالة بعد كل زمن معين (هنا سنستخدم <code>speed</code> حيث أن الدالة سيتم تنفيذها بعد كل 20ms) بداخل الدالة سنقوم بزيادة قيمة currentValue بـ 1 ونتحقق إذا وصلنا للقيمة الأعظمية للتقدم حيث نقوم بإيقاف تنفيذ الدالة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_49" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"progress"</span><span class="pln">
    </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{
        currentValue: 0,
        endValue: 85,
        speed: 20, // ms

        init() {
            let progress = setInterval(() =&gt;</span><span class="pln"> {
                this.currentValue++

                if (this.currentValue === this.endValue) {
                    clearInterval(progress)
                }
            }, this.speed)
        }
    }"
&gt;</span></pre>

<p>
	الآن إذا تصفحت ستجد أن القيمة تتغير من 0 إلى 85 كما هو مطلوب وعندما نصل إلى القيمة النهائية يتوقف التنفيذ. متبقي الآن ربط التنسيق الذي ذكرته في الأعلى بالقيمة الحالية، ولعمل هذا الشيء نحتاج إلى استخدام الموجه <code>x-bind</code> فهو يتيح ربط تعبير برمجي بخاصية من الخصائص في html، والخاصية التي سنتعامل معها هي style، هناك كتابة مختصرة لـ <code>x-bind</code> وهي رمز النقطتين <code>:</code> مثلما هو الحال مع <code>x-on</code> في الأحداث لذلك فبدل كتابة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_51" style=""><span class="pln">x-bind:style=""</span></pre>

<p>
	يمكن كتابة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_53" style=""><span class="pln">:style=""</span></pre>

<p>
	وبالتالي، لربط قيمة <code>currentValue</code> بخاصية <code>style</code> سنكتب:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_55" style=""><span class="pln">:style="`background: conic-gradient(slategray ${currentValue * 3.6}deg, #ddd 0deg)`"</span></pre>

<p>
	ليُصبح المكون بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7133_57" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"box"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"progress"</span><span class="pln">
        </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{
            currentValue: 0,
            endValue: 85,
            speed: 20, // ms

            init() {
                let progress = setInterval(() =&gt;</span><span class="pln"> {
                    this.currentValue++

                    if (this.currentValue === this.endValue) {
                        clearInterval(progress)
                    }
                }, this.speed)
            }
        }"

         :style="`background: conic-gradient(slategray ${currentValue * 3.6}deg, #ddd 0deg)`"
    &gt;
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"progress-inner"</span><span class="pln"> </span><span class="atn">x-text</span><span class="pun">=</span><span class="atv">"currentValue + '%'"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text"</span><span class="tag">&gt;</span><span class="pln">Alpine Js</span><span class="tag">&lt;/span&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	بهذا الشكل سيُصبح كل من الشريط والنص المكتوب في الوسط يتحرك من القيمة 0 إلى القيمة النهائية 85، يمكنك تعديل القيمة النهائية 85 وقيمة السرعة <code>speed</code> لمعاينة النتائج:
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="gif" data-fileid="142032" href="https://academy.hsoub.com/uploads/monthly_2024_01/animated-circular-progress-bar.gif.d75201bafe820c334003163ec0f24b9a.gif" rel=""><img alt="animated-circular-progress-bar.gif" class="ipsImage ipsImage_thumbnailed" data-fileid="142032" data-ratio="60.00" data-unique="ri15mwx1w" width="900" src="https://academy.hsoub.com/uploads/monthly_2024_01/animated-circular-progress-bar.thumb.gif.a5df03aaaf0abfaa7e28fb7389b391e3.gif"></a>
</p>

<h2 id="">
	خاتمة
</h2>

<p>
	في ختام هذا المقال، نستنتج أن إطار العمل Alpine.js يعد أداة قوية وبسيطة في تطوير تجارب المستخدم الديناميكية على الويب. قدمت الأمثلة التي استعرضناها في هذا السياق نظرة عامة على قوة وسهولة استخدام Alpine.js في تحقيق العديد من الوظائف الديناميكية دون الحاجة إلى اللجوء إلى <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AA%D9%89-%D9%86%D8%B3%D8%AA%D8%B9%D9%85%D9%84-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-%D9%84%D9%84%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-javascript-r477/" rel="">أطر عمل JavaScript</a> الكبيرة والمعقدة.
</p>

<p>
	تعتبر قدرة Alpine.js على توفير عمليات DOM الديناميكية والربط الفعّال بين العناصر والبيانات من خلال السماح بالتفاعل المباشر والتحكم السهل، مميزة بشكل خاص. التعابير البرمجية القصيرة والبنية البسيطة تجعل من السهل إدماجه في مشاريع الويب المختلفة دون تعقيدات زائدة.
</p>

<p>
	من خلال الأمثلة البسيطة التي قمنا بإنشائها، يمكن للمطورين الآن البدء بفهم كيفية استخدام Alpine.js في مشاريعهم الشخصية أو العملية. عليهم استكشاف الميزات الإضافية واستخدام الإمكانيات الكاملة لهذا الإطار لتحسين تفاعل المستخدم وتبسيط التجارب على الويب.
</p>

<h2 id="-1">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/javascript/" rel="">دليل تعلم لغة جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AA%D9%89-%D9%86%D8%B3%D8%AA%D8%B9%D9%85%D9%84-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-%D9%84%D9%84%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-javascript-r477/" rel="">متى نستعمل إطار عمل للتطوير باستخدام JavaScript</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%B5%D9%81%D8%B1-%D8%AD%D8%AA%D9%89-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81-r2046/" rel="">تعلم لغة جافا سكريبت من الصفر حتى الاحتراف</a>
	</li>
</ul>

<p>
	 
</p>
]]></description><guid isPermaLink="false">2229</guid><pubDate>Fri, 19 Jan 2024 12:04:04 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Alpine.js</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-alpinejs-r2214/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_01/----Alpine.js-d1-1.png.813acd9f1306088179d242f620419000.png" /></p>
<p>
	سنتعلم في هذه السلسلة من المقالات كيفية التعامل مع إطار العمل Alpine.js وسنبني نموذج <abbr title="Minimum Viable Product | المنتج الفعال القاعدي"><abbr title="Minimum Viable Product | المنتج الفعال القاعدي">MVP</abbr></abbr> مصغر يحاكي بعض ما تفعله Alpine.js من الصفر بهدف تعلم جافا سكريبت JavaScript وفهم آلية عمل هذا الإطار وتبسيط المفاهيم المرتبطة به.
</p>

<h2 id="alpinejs-1">
	ما هو Alpine.js؟
</h2>

<p>
	إن كنت لم تسمع عن هذا الإطار <a href="https://alpinejs.dev" rel="external nofollow">Alpine.js</a> من قبل فهو إطار عمل للغة جافا سكريبت <a href="https://wiki.hsoub.com/JavaScript" rel="external">JavaScript</a> صغير الحجم يساعد مطوري الويب كثيرًا ويمكّنهم من إضافة بعض التأثيرات التفاعلية على <a href="https://academy.hsoub.com/programming/html/%D8%A8%D8%B9%D8%B6-%D8%A7%D9%84%D8%B9%D9%86%D8%A7%D8%B5%D8%B1-%D9%88%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D9%85%D9%87%D9%85%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-html-r1895/" rel="">عناصر HTML</a> وعلى صفحات الويب بشيفرات بسيطة من خلال العناصر نفسها، وكما هو موضح في <a href="https://alpinejs.dev/start-here" rel="external nofollow">صفحة التوثيق</a> الخاصة بالإطار فإن Alpine.js يعد أداة قوية وبسيطة لتكوين السلوك مباشرة في شيفرة HTML التي تكتبها، يمكنك التفكير فيه على أنه مشابه لمكتبة <a href="https://academy.hsoub.com/programming/javascript/jquery/" rel="">jQuery</a> لكن للويب الحديث كما يوفر Alpine بُنية تفاعلية مثل أطر العمل والمكتبات الشهيرة مثل <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1664/" rel="">Vue</a> و <a href="https://academy.hsoub.com/programming/javascript/react/%D9%85%D8%A7-%D9%87%D9%8A-react%D8%9F-r773/" rel="">React</a> لكن بكلفة وجهد أقل بكثير، وإن كنت قد استخدمت <a href="https://academy.hsoub.com/programming/css/bootstrap/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-bootstrap-%D9%88-tailwind-css-r1595//" rel="">Tailwind</a> للغة <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> فهدف إطار العمل Alpine.js مشابه لها لكنه للغة JavaScript.
</p>

<p>
	يتميز إطار العمل Alpine.js كذلك بسهولة الاستخدام فهو يمكن المستخدم من تحقيق التفاعل بشكل فعّال دون الحاجة إلى الاعتماد على مكتبات JavaScript كبيرة أو معقدة، ودون الحاجة إلى إعادة تحميل الصفحة. كما يتميز Alpine.js بالتكامل السهل مع <a href="https://academy.hsoub.com/programming/html/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%88%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D8%B5%D9%81%D8%AD%D8%A9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A7%D8%AA-html-r1908/" rel="">صفحات HTML</a> المبنية بالفعل، مما يجعله خيارًا جيدًا للمشاريع الصغيرة إلى المتوسطة.
</p>

<h3 id="alpinejs-2">
	مبدأ عمل Alpine.js
</h3>

<p>
	يعتمد Alpine.js على فكرة الديناميكية الخفيفة، حيث يُضاف السلوك التفاعلي مباشرة إلى عناصر HTML، ويمكّنك من تعريف المتغيرات والدوال المرتبطة بالواجهة مباشرة في <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D9%81%D8%B1%D9%8A%D9%82-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%B3%D9%85%D8%A7%D8%AA-attributes-%D9%81%D9%8A-html-%D9%88%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-properties-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1116/" rel="">سمات HTML</a> مما يقلل من الحاجة إلى كتابة الكثير من الأكواد البرمجية.
</p>

<h3 id="alpinejs-3">
	ميزات Alpine.js
</h3>

<ol>
	<li>
		<p>
			<strong>سهولة التكامل:</strong> إذ يُدمج Alpine.js بسهولة مع صفحات HTML المبنية مسبقًا، ويتيح للمطورين إضافة تفاعل المستخدم بسرعة دون الحاجة إلى تغيير الهيكل الأساسي للصفحة.
		</p>
	</li>
	<li>
		<p>
			<strong>بنية بسيطة:</strong> يستخدم الإطار بنية بسيطة تتيح للمطورين فهمها بسرعة والبدء في استخدامها دون الحاجة إلى تعلم مفاهيم معقدة.
		</p>
	</li>
	<li>
		<p>
			<strong>تحكم ديناميكي:</strong> يسمح Alpine.js بربط العناصر بشكل ديناميكي بينما يُحدّث التطبيق، ما يمكن من بناء تطبيقات الصفحة الواحدة الصفحة SPA وإضافة تفاعل مستمر دون إعادة تحميل الصفحة.
		</p>
	</li>
</ol>

<h2 id="alpinejsvuereactangular">
	الفرق بين Alpine.js وأطر العمل Vue و React و Angular
</h2>

<p>
	سأذكر مقارنة سريعة بين Alpine وأشهر <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-framework/" rel="">أطر عمل</a> ومكتبات لغة جافاسكريبت:
</p>

<ol>
	<li>
		<p>
			<strong>Vue.js و React:</strong>
		</p>

		<ul>
			<li>
				Alpine.js أصغر حجمًا ويمكن تضمينه بسهولة في صفحات HTML بينما Vue.js و React يتطلبان هياكل مشروع معقدة أكثر.
			</li>
			<li>
				Alpine.js يستند إلى تقنية JavaScript الأساسية المدمجة في المتصفح دون الحاجة إلى ترجمة أو بناء مسبق، بينما Vue.js و React يتطلبان تحويل الشيفرة إلى شيفرة JavaScript قابلة للتنفيذ.
			</li>
		</ul>
	</li>
	<li>
		<p>
			<strong>Angular:</strong>
		</p>

		<ul>
			<li>
				Angular يقدم إمكانيات كبيرة لتطوير تطبيقات الويب الكبيرة والمعقدة، بينما يناسب Alpine.js المشاريع الصغيرة والمتوسطة.
			</li>
			<li>
				Angular يتطلب هياكل مشروع محددة ويتميز بتفصيل وتعقيد الإعدادات، بينما يعتمد Alpine.js على البساطة وسهولة الاستخدام.
			</li>
		</ul>
	</li>
</ol>

<h2 id="alpinejs-4">
	كيفية استخدام Alpine.js
</h2>

<p>
	سنبدأ التعرف على إطار عمل Alpine.js من خلال مثال بسيط وهو عبارة عن عداد يتكون من زرين أحدهما يقوم بزيادة قيمة العداد والثاني يقوم بإنقاصها، سنقوم بإنشاء ملف HTML بالاسم index.html ونضع بداخله بنية العداد كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4151_18" style=""><span class="com">&lt;!--  index.html --&gt;</span><span class="pln">

</span><span class="tag">&lt;html&gt;</span><span class="pln">

    </span><span class="tag">&lt;div&gt;</span><span class="pln">
            </span><span class="tag">&lt;button&gt;</span><span class="pln">+</span><span class="tag">&lt;/button&gt;</span><span class="pln">
            </span><span class="tag">&lt;span&gt;&lt;/span&gt;</span><span class="pln">
            </span><span class="tag">&lt;button&gt;</span><span class="pln">-</span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">defer</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	كما تلاحظ فبنية الملف بسيطة، فهو يحتوي فقط على وسم <a href="https://wiki.hsoub.com/HTML/html" rel="external"><code>html</code></a> بداخله قسم لبنية العداد، ووسم <a href="https://wiki.hsoub.com/HTML/script" rel="external"><code>script</code></a> لتضمين ملف Alpine.js، والعداد نفسه عبارة عن حاوية بداخلها زرين وعنصر <code><a href="https://wiki.hsoub.com/HTML/span" rel="external">span</a></code>، الزر الأول لزيادة قيمة العداد والزر الثاني لإنقاص قيمة العداد، بالإضافة لعنصر  span لعرض قيمة العداد.
</p>

<p>
	ولاستخدام Alpine.js نبدأ أولاً بالمُوجّه <code>x-data</code> وتكون قيمته عبارة عن كائن، نضع بداخله البيانات الخاصة بالمكون والتي نريد التعامل معها، يمكن أيضاً كتابة بعض التوابع بداخله، وبهذا الشكل ستتعرف Alpine على المكون ويمكن كتابة أي شيء توفره Alpine بداخل الحاوية، كما يمكن الوصول لقيم بيانات الكائن <code>data</code> والتعديل عليها بشكل ديناميكي دون تحديث الصفحة، تتحدث حالة المكون تلقائيًا مع كل تغيير، ولعرض قيمة الخاصية <code>count</code> التي تعبر عن قيمة العداد نستخدم المُوجّه <code>x-text</code>، وفي الزرين نستخدم <code>click@</code> للاستماع إلى حدث النقر على الأزرار ثم نقوم بالمعالجة على حسب الزر (في زر الزيادة نقوم بزيادة قيمة <code>count</code> بقيمة واحد، وفي زر الإنقاص نقوم بإنقاص قيمة <code>count</code> بقيمة واحد) بحيث تُصبح هيكلية شيفرة HTML بهذا الشكل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4151_20" style=""><span class="com">&lt;!--  index.html --&gt;</span><span class="pln">

</span><span class="tag">&lt;html&gt;</span><span class="pln">

    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{ count: 0 }"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;button</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"count++"</span><span class="tag">&gt;</span><span class="pln">+</span><span class="tag">&lt;/button&gt;</span><span class="pln">
            </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">x-text</span><span class="pun">=</span><span class="atv">"count"</span><span class="tag">&gt;&lt;/span&gt;</span><span class="pln">
            </span><span class="tag">&lt;button</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"count--"</span><span class="tag">&gt;</span><span class="pln">-</span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">defer</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	يخبر الموجه <code>x-data</code> إطار Alpine بتهيئة المكوّن الجديد بكائن البيانات المعرّف والمحدّد مسبقًا، أما الموجه <code>click@</code> فما هو إلا اختصار إلى <code>x-on:click</code> وهذا الموجه يستخدم للاستماع إلى حدث معين على عنصر ما، ويمكن استخدام أي حدث على حسب الحالة مثل <code>submit@</code> أو <code>mouseenter@</code> وغير ذلك. وأخيرًا، يضبط الموجه <code>x-text</code> محتوى نص العنصر على نتيجة تعبير برمجي معين.
</p>

<p>
	بعد فتح الصفحة على المتصفح وتجربة الكود سنحصل على النتيجة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="gif" data-fileid="141283" href="https://academy.hsoub.com/uploads/monthly_2024_01/counter-with-alpine-js.gif.803d1ee7316d7d1176c8d894031e2fe8.gif" rel=""><img alt="counter with alpine js" class="ipsImage ipsImage_thumbnailed" data-fileid="141283" data-unique="2oltanmj6" style="width: 330px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2024_01/counter-with-alpine-js.gif.803d1ee7316d7d1176c8d894031e2fe8.gif"> </a>
</p>

<h2 id="alpinejs-5">
	تطبيق عملي باستخدام Alpine.js
</h2>

<p>
	بعد أن أخذنا نظرة مبدئية على Alpine وكتبنا أول مثال بسيط بها، سنأتي لإنشاء <a href="https://academy.hsoub.com/entrepreneurship/general/%D8%A7%D8%A8%D8%AF%D8%A3-%D8%B5%D8%BA%D9%8A%D8%B1%D8%A7-%D8%B1%D8%AD%D9%84%D8%A9-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D8%B9%D9%86-%D8%A7%D9%84%D9%85%D9%86%D8%AA%D8%AC-%D8%A7%D9%84%D9%81%D8%B9%D8%A7%D9%84-%D8%A7%D9%84%D9%82%D8%A7%D8%B9%D8%AF%D9%8A-mvp-r167/" rel="">نموذج <abbr title="Minimum Viable Product | المنتج الفعال القاعدي"><abbr title="Minimum Viable Product | المنتج الفعال القاعدي">MVP</abbr></abbr> مُصغر</a> من الصفر بهدف التعلم وفهم الطريقة أو الآلية التي يعمل بها Alpine، سنبدأ خطوة بخطوة حتى نصل للمنتج النهائي، سنرجع للمثال السابق، ونزيل سطر تضمين المكتبة، ونقوم بكتابة <a href="https://academy.hsoub.com/javascript/" rel="">شيفرات JavaScript</a> خاصة بنا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4151_22" style=""><span class="com">&lt;!-- index.html --&gt;</span><span class="pln">

</span><span class="tag">&lt;html&gt;</span><span class="pln">

    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{ count: 0 }"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;button</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"count++"</span><span class="tag">&gt;</span><span class="pln">+</span><span class="tag">&lt;/button&gt;</span><span class="pln">
            </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">x-text</span><span class="pun">=</span><span class="atv">"count"</span><span class="tag">&gt;&lt;/span&gt;</span><span class="pln">
            </span><span class="tag">&lt;button</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"count--"</span><span class="tag">&gt;</span><span class="pln">-</span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;script&gt;</span><span class="pln">

        </span><span class="com">// سنكتب الشيفرات الخاصة بنا هنا</span><span class="pln">

    </span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	بطبيعة الحال الآن إذا قمت بتجربة الضغط على الأزرار فلن تعمل معك خاصية العداد، لأن Alpine.js لم يعد لها وجود في الملف.
</p>

<p>
	يقوم إطار العمل Alpine.js أو أطر العمل الحديثة مثل Vue وغيرها على مبدأين أساسيين وهما:
</p>

<ol>
	<li>
		مراقبة أو تتبع بعض البيانات.
	</li>
	<li>
		تحديث شجرة DOM عندما تتغير تلك البيانات.
	</li>
</ol>

<p>
	بغض النظر عن المكتبة أو إطار العمل أو كيفية تحقيق ذلك، إلا أن هذين المبدأين هما الأساس في العمل. سنحاول لذا سنحاول في إنشائنا لهذا النموذج المصغر الاعتماد عليهما، قد يُخيل لك أن الأمر بسيط جداً لكن هناك أشياء كثيرة تحدث في الخلفية لتحقيق تلك البساطة في الأخير.
</p>

<h3 id="alpinejs-6">
	فهم كيفية عمل التفاعلية في إطار العمل Alpine.js
</h3>

<p>
	نعود لملف HTML الخاص بنا وفي الجزء الذي حددنا أننا سنكتب فيه شيفرة JavaScript سنحاول تحقيق أول مبدأ وأول خُطوة هي تكوين كائن البيانات انطلاقا من العنصر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_24" style=""><span class="kwd">let</span><span class="pln"> root </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'[x-data]'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> dataString </span><span class="pun">=</span><span class="pln"> root</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'x-data'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">dataString</span><span class="pun">})`)</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">data</span><span class="pun">);</span></pre>

<p>
	في السطر الأول حددنا عُنصر أو حاوية المكون الأساسية عبر استخدام التابع <code>querySelector</code> وعبر الخاصية <code>x-data</code> ثم قمنا بتخزينه في المتغير <code>root</code> بعد أن أصبح العُنصر مخزن لدينا ككائن. استخدمنا التابع <code>getAttribute</code> لجلب قيمة الخاصية <code>x-data</code> وقمنا بتخزينها في متغير بالاسم <code>dataString</code>، لكن قيمته عبارة عن سلسلة نصية إذا طبعت القيمة من خلال <a href="https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B7%D9%88%D9%90%D9%91%D8%B1-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%AF%D9%8A%D8%AB%D8%A9-r541/" rel="">الطرفية console</a> ستحصل على:
</p>

<pre class="ipsCode">'{ count: 0 }'
</pre>

<p>
	لذلك استخدمنا بعدها الدالة <a href="https://wiki.hsoub.com/JavaScript/eval" rel="external"><code>eval</code></a> لتحويل السلسلة النصية إلى كائن JavaScript، وإذا قمت بتصفح ملف index.html بعد إضافة الشيفرات السابقة ستحصل في الطرفية console على الناتج:
</p>

<pre class="ipsCode">{count: 0}
</pre>

<p>
	بهذا الشكل حققنا أول خطوة وهي أن البيانات أصبحت متاحة لدينا في JavaScript، والآن يمكن التعديل عليها ومراقبتها. سنقوم في الخطوة القادمة بتحسين كتابة الكود السابق، وذلك عبر استخراج دالة سميناها <code>getInitialData</code> ليُصبح الكود بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_26" style=""><span class="kwd">let</span><span class="pln"> root </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'[x-data]'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> getInitialData</span><span class="pun">()</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> getInitialData</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> dataString </span><span class="pun">=</span><span class="pln"> root</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'x-data'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">dataString</span><span class="pun">})`)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنقوم في الخطوة القادمة بإنشاء دالة تقوم بتحديث <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%B4%D8%AC%D8%B1%D9%8A%D8%A9-%D9%84%D9%80-dom-r646/" rel="">لشجرة DOM</a>، وستجد أننا نستخدم الطريقة التالية في كتابة الشيفرة والتوسع:
</p>

<ol>
	<li>
		استدعاء الواجهة البرمجية (في حالتنا ستكون دالة)
	</li>
	<li>
		إنشاء الواجهة البرمجية
	</li>
	<li>
		تحسين الشيفرة أو إعادة بنائها بشكل أفضل
	</li>
</ol>

<p>
	نعود للشيفرة السابقة ونزيل سطر طباعة البيانات، ونضيف الدالة التي نريد إنشاءها وهي <code>refreshDOM()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_28" style=""><span class="kwd">let</span><span class="pln"> root </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'[x-data]'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> getInitialData</span><span class="pun">()</span><span class="pln">
refreshDOM</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> getInitialData</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> dataString </span><span class="pun">=</span><span class="pln"> root</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'x-data'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">dataString</span><span class="pun">})`)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الآن نُنشئ الدالة <code>refreshDOM</code> وسيكون الهدف منها تحديث شجرة DOM:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_30" style=""><span class="kwd">function</span><span class="pln"> refreshDOM</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    walkDOM</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> el </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">el</span><span class="pun">.</span><span class="pln">outerHTML</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما تلاحظ فإن الدالة <code>refreshDOM</code> تقوم فقط باستدعاء دالة أخرى تُسمى <code>walkDOM</code> سنقوم بإنشائها بعد حين، هذه الدالة تقوم بالمرور على عناصر مكون التعداد انطلاقا من العنصر الممرر في المعامل الأول ونحن حددنا <code>root</code> وهو العنصر الخاص بمكون العداد، وفي المعامل الثاني تقبل <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%B1%D8%AF%D9%88%D8%AF-%D8%A7%D9%84%D9%86%D8%AF%D8%A7%D8%A1-callbacks-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r914/" rel="">دالة رد نداء callback function</a> يتم تنفيذها من داخل الدالة <code>walkDOM</code>، في حالتنا رد النداء callback عبارة عن <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%88%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B3%D9%87%D9%85%D9%8A%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r782/" rel="">دالة سهمية</a> تستقبل معامل <code>el</code> وتقوم بطباعة <code>outerHTML</code> الخاص به (بمعنى العُنصر بشكل كامل وسم البداية والنهاية بالإضافة إلى المحتوى الداخلي له)، وهنا استخدمنا تعليمة الطباعة بغرض الشرح وتبسيط الفهم لكننا سنقوم بتغيير محتوى الدالة السهمية لاحقًا.
</p>

<p>
	كما أسلفت بالذكر فإن الدالة <code>walkDOM</code> ستعبر على عناصر المكون فقط انطلاقا من عُنصر المكون نفسه، ثم الابن الأول للعنصر وإن كان للابن أبناء تمر عبرهم أيضًا، وهكذا كل ما تجد أن للعنصر الحالي أبناء تعبر عليهم وفي كل مرة تعود تعبر على عناصر الابن الموالي للأب حتى لا تجد عناصر تعبر عليهم. سنستخدم في بنائنا للدالة <code>walkDOM</code> مفهوم يُسمى <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF%D9%8A%D8%A9-recursion-r1387/" rel="">التعاودية</a> وهو مفهوم برمجي متبع في معظم لغات البرمجة، يسمح باستدعاء الدالة لنفسها بمعنى آخر تنفيذ الدالة كجزء من الدالة نفسها، وسيساعدنا في مسألة العبور على العناصر المتداخلة في المكون.
</p>

<p>
	الآن بعد أن وضحنا ما الذي سنقوم به، نكتب الدالة <code>walkDOM</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_32" style=""><span class="kwd">function</span><span class="pln"> walkDOM</span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    callback</span><span class="pun">(</span><span class="pln">el</span><span class="pun">)</span><span class="pln">

    el </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">firstElementChild
    </span><span class="kwd">while</span><span class="pun">(</span><span class="pln">el</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        walkDOM</span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln">

        el </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">nextElementSibling
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما تلاحظ فالدالة <code>walkDOM</code> لا تحتوي على أسطر كثيرة، فهي تقوم أولًا بتنفيذ دالة <code>callback</code> الممررة كمعامل ثاني على المعامل الأول ودالة <code>callback</code> ستقوم بطباعة العنصر فقط، ثم في السطر الثاني نُغير العنصر لأول ابن للعُنصر الأساسي باستخدام الخاصية <code>firstElementChild</code>، ثم نقوم بتنفيذ <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1306/" rel="">حلقة <code>while</code></a> للمرور على كافة الأبناء ونستخدم الخاصية <code>nextElementSibling</code> التي تجلب العُنصر الموالي (الأخ) للعنصر الحالي. ونستدعي الدالة <code>walkDOM</code> من داخل الحلقة حتى نضمن العبور على أبناء العنصر الحالي في الحلقة وبهذا الشكل نكون قد استخدمنا التعاودية للعبور على كافة العناصر المتداخلة.
</p>

<p>
	الآن إذا قمت بتصفح الملف index.html من خلال المتصفح وفتحت نافذة الطرفية console ستجد أنه كافة عناصر المكون ستطبع، وإن قمت بالتعديل على هيكلية عناصر المكون بإضافة عناصر HTML متداخلة ستطبع كما هو متوقع وهذا هو الناتج:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="141287" href="https://academy.hsoub.com/uploads/monthly_2024_01/walkDOM-To-Print-Component-Elements.png.6aa566dae7d3c45bb8a2df27161c116c.png" rel=""><img alt="walkdom to print component elements" class="ipsImage ipsImage_thumbnailed" data-fileid="141287" data-unique="q6lavywyb" src="https://academy.hsoub.com/uploads/monthly_2024_01/walkDOM-To-Print-Component-Elements.thumb.png.b8814f5eed61d72fe445ce26e174193e.png"> </a>
</p>

<p>
	بما أننا استطعنا المرور على جميع عناصر المكون جاء الدور الآن على تغيير بُنية دالة <code>callback</code> التي نقوم بتنفيذها أثناء العبور فنحن لا نريد الطباعة، وإنما نريد تغيير نص العناصر التي بها الخاصية <code>x-text</code> بالبيانات الموافقة لها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_34" style=""><span class="pln">walkDOM</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> el </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">el</span><span class="pun">.</span><span class="pln">hasAttribute</span><span class="pun">(</span><span class="str">'x-text'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        el</span><span class="pun">.</span><span class="pln">innerText </span><span class="pun">=</span><span class="pln"> </span><span class="str">"foo"</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	استخدمنا التابع <code>hasAttribute</code> للتحقق أن العنصر يملك خاصية بالاسم <code>x-text</code> ثم باستخدام خاصية <code>innerText</code> غيرنا النص الموافق له، ستجد أن النص الموافق للعنصر <code>span</code> والذي به الخاصية <code>x-text</code> تغير إلى foo لكننا نريد وضع القيمة الخاصة بما تحمله <code>x-text</code>، في حالتنا ستكون قيمة العداد <code>count</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_36" style=""><span class="kwd">let</span><span class="pln"> expression </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'x-text'</span><span class="pun">)</span></pre>

<p>
	استخدمنا التابع <code>getAttribute</code> لجلب القيمة ستكون عبارة عن سلسلة نصية لاسم البيانات (في حالتنا هي <code>count</code> في مثال آخر ستكون ما يتم كتابته بداخل الخاصية <code>x-text</code> قد تكون تعبير برمجي).
</p>

<p>
	الآن سنجلب القيمة الموافقة للتعبير expression ونضعها كنص للعُنصر، سنستخدم الدالة <code>eval</code> كما فعلنا سابقًا لكن لا يمكن كتابة التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_38" style=""><span class="pln">el</span><span class="pun">.</span><span class="pln">innerText </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">expression</span><span class="pun">})`)</span></pre>

<p>
	لأن القيمة ليست متاحة كمتغير وإنما موجودة ضمن الكائن <code>data</code> للوصول إليها نستخدم التعليمة <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with" rel="external nofollow"><code>with</code></a> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_40" style=""><span class="pln">el</span><span class="pun">.</span><span class="pln">innerText </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`</span><span class="kwd">with</span><span class="pln"> </span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">expression</span><span class="pun">})</span><span class="pln"> </span><span class="pun">}`)</span></pre>

<p>
	ملاحظة: إن التعليمة <code>with</code> حسب التوثيق مهملة ولا يُنصح باستخدامها وقد يتم إزالتها بسبب مشاكل دعم المتصفحات والتوافقية، وهناك طرق أخرى بطبيعة الحال لكن للسهولة ولأغراض تعليمية سنستمر على هذه الطريقة فهي لازالت تعمل.
</p>

<p>
	الآن أصبح بالإمكان تحديث شجرة DOM عبر الدالة التي بنيناها والتي أصبح شكلها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_42" style=""><span class="kwd">function</span><span class="pln"> refreshDOM</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    walkDOM</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> el </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">el</span><span class="pun">.</span><span class="pln">hasAttribute</span><span class="pun">(</span><span class="str">'x-text'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">let</span><span class="pln"> expression </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'x-text'</span><span class="pun">)</span><span class="pln">
            el</span><span class="pun">.</span><span class="pln">innerText </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`</span><span class="kwd">with</span><span class="pln"> </span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">expression</span><span class="pun">})</span><span class="pln"> </span><span class="pun">}`)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وأصبحت شيفرة جافاسكربت بالكامل كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_44" style=""><span class="kwd">let</span><span class="pln"> root </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'[x-data]'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> getInitialData</span><span class="pun">()</span><span class="pln">
refreshDOM</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> getInitialData</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> dataString </span><span class="pun">=</span><span class="pln"> root</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'x-data'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">dataString</span><span class="pun">})`)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> refreshDOM</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    walkDOM</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> el </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">el</span><span class="pun">.</span><span class="pln">hasAttribute</span><span class="pun">(</span><span class="str">'x-text'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">let</span><span class="pln"> expression </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'x-text'</span><span class="pun">)</span><span class="pln">
            el</span><span class="pun">.</span><span class="pln">innerText </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`</span><span class="kwd">with</span><span class="pln"> </span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">expression</span><span class="pun">})</span><span class="pln"> </span><span class="pun">}`)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> walkDOM</span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    callback</span><span class="pun">(</span><span class="pln">el</span><span class="pun">)</span><span class="pln">

    el </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">firstElementChild
    </span><span class="kwd">while</span><span class="pun">(</span><span class="pln">el</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        walkDOM</span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln">

        el </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">nextElementSibling
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الآن إذا فتحت الصفحة على المتصفح ستلاحظ أن العداد يأخذ القيمة الابتدائية وهي 0 وهذا لأننا نقوم بتنفيذ <code>refreshDOM</code> بعد جلب البيانات:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="141285" href="https://academy.hsoub.com/uploads/monthly_2024_01/refreshDOM-and-update-elements-with-x-text.PNG.e2b31d6006e1f163efa35a84d346a793.PNG" rel=""><img alt="refreshdom and update elements with x text" class="ipsImage ipsImage_thumbnailed" data-fileid="141285" data-unique="yjodvw9n1" src="https://academy.hsoub.com/uploads/monthly_2024_01/refreshDOM-and-update-elements-with-x-text.thumb.PNG.f7c89f53792f1f9401c655703e82205b.PNG"> </a>
</p>

<p>
	يمكنك فتح نافذة الطرفية ومحاولة تغيير قيمة count إلى قيمة أخرى مثلًا:
</p>

<pre class="ipsCode" id="ips_uid_4151_48">data.count = 5</pre>

<p>
	بهذا الشكل ستغيير القيمة الفعلية للعداد، لكن لن تتحدث القيمة في العنصر الموافق، ونحتاج إلى استدعاء <code>refreshDOM</code> بعد تعديل القيمة حتى تتحدث في الصفحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_50" style=""><span class="pln">data</span><span class="pun">.</span><span class="pln">count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
refreshDOM</span><span class="pun">()</span></pre>

<p>
	وستلاحظ أن القيمة تتغير بمجرد استدعاء الدالة، وكلما غيرت قيمة <code>data.count</code> إلى قيمة أخرى واستدعيت الدالة <code>refreshDOM</code> ستستجيب العناصر، وهذا ما ذكرته في البداية عن المبدأين (مراقبة البيانات وتحديث شجرة DOM عندما تتغير البيانات) كما هو موضح أدناه:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="gif" data-fileid="141286" href="https://academy.hsoub.com/uploads/monthly_2024_01/update-data-and-call-refreshDOM.gif.2e0123998232a5573671103934303405.gif" rel=""><img alt="update data and call refreshdom" class="ipsImage ipsImage_thumbnailed" data-fileid="141286" data-unique="iwhj1y55t" src="https://academy.hsoub.com/uploads/monthly_2024_01/update-data-and-call-refreshDOM.thumb.gif.911fc5ad7c9376736bb9c7c26ec5e2c6.gif"> </a>
</p>

<p>
	لكن كما تلاحظ فإن عملية تحديث شجرة DOM لا تعمل بشكل تلقائي أو ديناميكي، والخطوة التالية هي تحقيق ذلك، بحيث عند تعديل البيانات يتم مباشرة تحديث شجرة DOM دون أن نفعل ذلك بشكل صريح. سيساعدنا الكائن <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy" rel="external nofollow"><code>Proxy</code></a> في هذه المهمة.
</p>

<p>
	قبل أن نستعمله في الشيفرة الخاصة بنا سنفتح المتصفح ثم نافذة الطرفية ونعرف كائن بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_52" style=""><span class="kwd">let</span><span class="pln"> myData </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">x</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">}</span></pre>

<p>
	ثم سنقوم بإنشاء كائن <code>Proxy</code> ونوكل له مهمة التفاعل مع الكائن myData، يتيح لنا كائن الوكيل Proxy إعادة تعريف التوابع المتاحة للكائنات، فمثلاً يمكن إعادة تعريف التابع <code>get</code> و<code>set</code> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4151_54" style=""><span class="kwd">let</span><span class="pln"> proxy </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Proxy</span><span class="pun">(</span><span class="pln">myData</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">get</span><span class="pun">(</span><span class="pln">target</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'getting ...'</span><span class="pun">);</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> target</span><span class="pun">[</span><span class="pln">key</span><span class="pun">];</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    </span><span class="kwd">set</span><span class="pun">(</span><span class="pln">target</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'setting ...'</span><span class="pun">);</span><span class="pln"> target</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> value</span><span class="pun">;}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وعند تعريف الوكيل تُصبح خصائص الكائن الأساسي متاحة لكائن الوكيل بالشكل التالي عند جلب قيمة الخاصية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8340_35" style=""><span class="pln">proxy</span><span class="pun">.</span><span class="pln">x</span></pre>

<p>
	سنفذ ما حددناه داخل <code>get</code> وترى الناتج التالي:
</p>

<pre class="ipsCode">getting ...
2
</pre>

<p>
	ونفس الأمر عند التعديل:
</p>

<pre class="ipsCode">proxy.x = 10
setting ...
10
</pre>

<p>
	وكما تلاحظ أصبح كائن الوكيل يُغلف الكائن الأساسي الخاص بنا، بطريقته الخاصة، كان هذا شرح بسيط لكائن الوكيل، قد تقول فيما ستفيدني هذه الميزة! في الواقع تساعدك هذه الميزة في تغليف كائن البيانات الخاص بك بكائن وكيل بحيث تعيد تعريف التابع <code>set</code> وتستدعي بداخله الدالة <code>refreshDOM</code> بحيث عندما تتغير قيمة البيانات يتم تلقائيًا استدعاء الدالة ويتم تحديث شجرة DOM.
</p>

<p>
	سنقوم أولا بإعادة تعريف المتغير <code>data</code> إلى <code>rawData</code> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8340_33" style=""><span class="kwd">let</span><span class="pln"> rawData </span><span class="pun">=</span><span class="pln"> getInitialData</span><span class="pun">()</span></pre>

<p>
	ثم نُعرف متغير بالاسم <code>data</code> بحيث نُسند له كائن الوكيل لكن سنقوم بإنشاء دالة تقوم بذلك نُسميها <code>observe</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8340_31" style=""><span class="kwd">let</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> observe</span><span class="pun">(</span><span class="pln">rawData</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> observe</span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Proxy</span><span class="pun">(</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pun">(</span><span class="pln">target</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            target</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> value
            refreshDOM</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بحيث تُصبح شيفرة JavaScript بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8340_29" style=""><span class="kwd">let</span><span class="pln"> root </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'[x-data]'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> rawData </span><span class="pun">=</span><span class="pln"> getInitialData</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> observe</span><span class="pun">(</span><span class="pln">rawData</span><span class="pun">)</span><span class="pln">
refreshDOM</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> observe</span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Proxy</span><span class="pun">(</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pun">(</span><span class="pln">target</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            target</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> value
            refreshDOM</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> getInitialData</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> dataString </span><span class="pun">=</span><span class="pln"> root</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'x-data'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">dataString</span><span class="pun">})`)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> refreshDOM</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    walkDOM</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> el </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">el</span><span class="pun">.</span><span class="pln">hasAttribute</span><span class="pun">(</span><span class="str">'x-text'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">let</span><span class="pln"> expression </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'x-text'</span><span class="pun">)</span><span class="pln">
            el</span><span class="pun">.</span><span class="pln">innerText </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`</span><span class="kwd">with</span><span class="pln"> </span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">expression</span><span class="pun">})</span><span class="pln"> </span><span class="pun">}`)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> walkDOM</span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    callback</span><span class="pun">(</span><span class="pln">el</span><span class="pun">)</span><span class="pln">

    el </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">firstElementChild
    </span><span class="kwd">while</span><span class="pun">(</span><span class="pln">el</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        walkDOM</span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln">

        el </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">nextElementSibling
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الآن إذا فتحنا الصفحة الخاصة بنا على المتصفح، ثم غيرنا البيانات من الطرفية كما فعلنا سابقًا:
</p>

<pre class="ipsCode">data.count = 5
</pre>

<p>
	ستتغير القيمة الفعلية وسيستجيب المكون للتغيير تلقائيًا. وهذا ما يسمى بالتفاعلية reactivity.
</p>

<h3 id="alpinejs-7">
	فهم كيفية معالجة الأحداث في Alpine.js
</h3>

<p>
	الخطوة القادمة هي معالجة الأحداث، فحتى اللحظة الحالية لا تفعل الأزرار أي شيء ولا تستجيب عند الضغط عليها، لتحقيق ذلك نحتاج إلى إنشاء دالة تقوم بتسجيل المستمعات، سنُسمي الدالة <code>registerListeners</code> ومن داخلها سنمر  على عناصر شجرة DOM باستعمال الدالة <code>walkDOM</code> كما فعلنا سابقًا وفي دالة <code>callback</code> إن كان العُنصر يملك خاصية بالاسم <code>click@</code> نُسجل مستمع على حدث النقر بالعُنصر والمعالج يكون حسب قيمة الخاصية <code>click@</code> المحددة في HTML:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8340_27" style=""><span class="pln">registerListeners</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> registerListeners</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    walkDOM</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> el </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">el</span><span class="pun">.</span><span class="pln">hasAttribute</span><span class="pun">(</span><span class="str">'@click'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">let</span><span class="pln"> expression </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'@click'</span><span class="pun">)</span><span class="pln">
            el</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'click'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">eval</span><span class="pun">(`</span><span class="kwd">with</span><span class="pln"> </span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">expression</span><span class="pun">})</span><span class="pln"> </span><span class="pun">}`)</span><span class="pln">
            </span><span class="pun">})</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الآن إذا فتحت الصفحة وجربت الضغط على الأزرار ستستجيب كما هو متوقع، وبهذا الشكل نكون قد وصلنا لنفس ما تقوم به Alpine ونفس المثال الذي بدأنا به.
</p>

<p>
	لكن إلى الآن النموذج الذي أنشأناه يستمع ويعالج فقط حدث النقر فماذا عن الأحداث الأخرى وماذا عن موجهات أخرى، إذ أضفنا الموجه <code>x-text</code> فقط وسنحاول في الخطوة القادمة تحقيق ذلك.
</p>

<p>
	نبدأ أولاً بالأحداث ولنُغير أولاً السطر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8340_25" style=""><span class="tag">&lt;button</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"count++"</span><span class="tag">&gt;</span><span class="pln">+</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	نقوم بربط زيادة العداد بالحدث <code>mouseenter</code> أي حدث تمرير مؤشر الفأرة على الزر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8340_23" style=""><span class="tag">&lt;button</span><span class="pln"> @</span><span class="atn">mouseenter</span><span class="pun">=</span><span class="atv">"count++"</span><span class="tag">&gt;</span><span class="pln">+</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	ثم سنعدل الشيفرة لتشمل ذلك، وبالتحديد سنعدل الدالة <code>registerListeners</code> في دالة <code>callback</code> الممررة للدالة <code>walkDOM</code> فبدل أن نبحث بشكل صريح عن الخاصية <code>click@</code> نمر على كافة الخصائص المتاحة في العُنصر فإن لم تكن الخاصية تبدأ بالرمز @ نتجاهلها وإلا فالخاصية عبارة عن ربط حدث بالعنصر، نجلب الخاصية والتي ستكون عبارة عن اسم الحدث مسبوق برمز @ فقط نزيل رمز @ ليُصبح لدينا اسم الحدث:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8340_21" style=""><span class="kwd">function</span><span class="pln"> registerListeners</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    walkDOM</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> el </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">el</span><span class="pun">.</span><span class="pln">attributes</span><span class="pun">).</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">attribute </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">attribute</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="str">'@'</span><span class="pun">))</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">let</span><span class="pln"> event </span><span class="pun">=</span><span class="pln"> attribute</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">'@'</span><span class="pun">,</span><span class="pln"> </span><span class="str">''</span><span class="pun">);</span><span class="pln">
            el</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="pln">event</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">eval</span><span class="pun">(`</span><span class="kwd">with</span><span class="pln"> </span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">attribute</span><span class="pun">.</span><span class="pln">value</span><span class="pun">})</span><span class="pln"> </span><span class="pun">}`)</span><span class="pln">
            </span><span class="pun">})</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نفس التوجه، فقط وسعنا المنطق ليشمل أحداث متعددة وليس فقط حدث النقر، الآن إذا فتحت الصفحة ومررت مؤشر الفأرة فوق زر الزيادة سيستجيب المكون للحدث وتزداد قيمة العداد. وبهذا الشكل جعلنا النموذج يقبل أحداث متنوعة بإمكانك تجربتها وستجد أن المكون يستجيب لها.
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="gif" data-fileid="141284" href="https://academy.hsoub.com/uploads/monthly_2024_01/listen-to-others-events.gif.886af4d87578c02e8016c94ec46d3c9d.gif" rel=""><img alt="listen to others events" class="ipsImage ipsImage_thumbnailed" data-fileid="141284" data-unique="jrbeqbye0" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2024_01/listen-to-others-events.thumb.gif.0b3687be963240a50340e1cdcca6f2c3.gif"> </a>
</p>

<p>
	نأتي الآن إلى مسألة زيادة الموجهات، سنضيف على سبيل المثال الموجه <code>x-show</code> الذي يعرض عُنصر حسب شرط معين نحدده له، أولاً نضيف عُنصر <code>span</code> جديد للمكون يعرض رسالة في حالة تجاوزت قيمة العداد مثلاً القيمة 5 وإذا كانت أقل لا يعرضها:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8340_18" style=""><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">x-show</span><span class="pun">=</span><span class="atv">"count &gt;</span><span class="pln"> 5"&gt;Greater than 5</span><span class="tag">&lt;/span&gt;</span></pre>

<p>
	ونقوم بتوسيع المنطق ليشمل هذا التعديل، وسنقوم بذلك على مستوى الدالة <code>refreshDOM</code>، فهي تنظر إلى الآن للخاصية x-text فقط.
</p>

<p>
	في البداية لنوسع الموجه الحالي ثم نضيف الموجه الجديد، لذا سنعرف كائن يحمل الموجهات المتاحة، بحيث تكون المفتاح فيه عبارة عن اسم الموجه وتكون القيمة <a href="https://academy.hsoub.com/programming/javascript/%D9%86%D8%B8%D8%B1%D8%A9-%D8%AA%D9%81%D8%B5%D9%8A%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B3%D9%87%D9%85%D9%8A%D8%A9-arrow-functions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r880/" rel="">دالة سهمية</a> موافقة له لتنفيذها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8340_16" style=""><span class="kwd">let</span><span class="pln"> directives </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">'x-text'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        el</span><span class="pun">.</span><span class="pln">innerText </span><span class="pun">=</span><span class="pln"> value
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ثم سنستخدم في الدالة <code>refreshDOM</code> بدالة <code>callback</code> نفس الطريقة التي استخدمناها مع الأحداث ونمر على كل خاصيات العنصر، ونتجاهل كل خاصية إذا لم تكن ضمن المفاتيح المعرفة في الكائن <code>directives</code>، أما إذا كانت موجودة فننفذ الدالة السهمية الموافقة لها ونمرر العُنصر والقيمة الموافقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8340_14" style=""><span class="kwd">function</span><span class="pln"> refreshDOM</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    walkDOM</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> el </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">el</span><span class="pun">.</span><span class="pln">attributes</span><span class="pun">).</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">attribute </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">(</span><span class="pln">directives</span><span class="pun">).</span><span class="pln">includes</span><span class="pun">(</span><span class="pln">attribute</span><span class="pun">.</span><span class="pln">name</span><span class="pun">))</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            directives</span><span class="pun">[</span><span class="pln">attribute</span><span class="pun">.</span><span class="pln">name</span><span class="pun">](</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`</span><span class="kwd">with</span><span class="pln"> </span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">attribute</span><span class="pun">.</span><span class="pln">value</span><span class="pun">})</span><span class="pln"> </span><span class="pun">}`))</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الآن بعدما وسعنا المنطق ليشمل موجهات أخرى نقوم بإضافة موجه <code>x-show</code> للكائن <code>directives</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8340_12" style=""><span class="kwd">let</span><span class="pln"> directives </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">'x-text'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        el</span><span class="pun">.</span><span class="pln">innerText </span><span class="pun">=</span><span class="pln"> value
    </span><span class="pun">},</span><span class="pln">
    </span><span class="str">'x-show'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        el</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">display </span><span class="pun">=</span><span class="pln"> value </span><span class="pun">?</span><span class="pln"> </span><span class="str">'block'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'none'</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	استخدمنا في الدالة السهمية الموافقة لـ <code>x-show</code> خاصية <code>display</code> من <code>style</code> التي تقوم بإخفاء العنصر إذا كانت القيمة <code>none</code> وإن كانت <code>block</code> يظهر العنصر، الآن إذا فتحت الصفحة ستجد أن الأحداث تستجيب والعداد تتغير قيمته، وإذا تجاوزت القيمة العدد 5 ظهرت الرسالة وإذا أنقصنا القيمة لتصبح أقل أو تساوي 5 اختفت الرسالة كما هو متوقع تمامًا:
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="gif" data-fileid="141282" href="https://academy.hsoub.com/uploads/monthly_2024_01/add-new-directive-like-x-show.gif.a8dc4637f868ebf120cacfeb83d5a1c3.gif" rel=""><img alt="add new directive like x show" class="ipsImage ipsImage_thumbnailed" data-fileid="141282" data-unique="fk7ng4ywq" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2024_01/add-new-directive-like-x-show.thumb.gif.8a1795d61df04c863ab3770dc9d48bf1.gif"> </a>
</p>

<p>
	الخطوة الأخيرة من هذا المقال ستكون بتحسين الكود، وذلك عبر إنشاء كائن بالاسم Alpine وإسناده إلى المتغير العام <code>window</code>، بحيث تصبح المتغيرات التي أنشأناها خصائص لهذا الكائن والدوال توابع له، وبداخله ننُشئ تابع بالاسم <code>start</code> يضم الأسطر الأولى لتشغيل النموذج. ثم نقوم باستخراج النموذج إلى ملف منفصل بالاسم alpine.js ثم نقوم باستدعائه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8340_8" style=""><span class="tag">&lt;html&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">x-data</span><span class="pun">=</span><span class="atv">"{ count: 0 }"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"count++"</span><span class="tag">&gt;</span><span class="pln">+</span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">x-text</span><span class="pun">=</span><span class="atv">"count"</span><span class="tag">&gt;&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"count--"</span><span class="tag">&gt;</span><span class="pln">-</span><span class="tag">&lt;/button&gt;</span><span class="pln">

    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">x-show</span><span class="pun">=</span><span class="atv">"count &gt;</span><span class="pln"> 5"&gt;Greater than 5</span><span class="tag">&lt;/span&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"./alpine.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	ويكون محتوى ملف alpine.js كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8340_6" style=""><span class="pln">window</span><span class="pun">.</span><span class="typ">Alpine</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    directives</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">'x-text'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            el</span><span class="pun">.</span><span class="pln">innerText </span><span class="pun">=</span><span class="pln"> value
        </span><span class="pun">},</span><span class="pln">
        </span><span class="str">'x-show'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            el</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">display </span><span class="pun">=</span><span class="pln"> value </span><span class="pun">?</span><span class="pln"> </span><span class="str">'block'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'none'</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">

    start</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">root </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'[x-data]'</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rawData </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">getInitialData</span><span class="pun">()</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">observe</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rawData</span><span class="pun">)</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">registerListeners</span><span class="pun">()</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refreshDOM</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">

    getInitialData</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">let</span><span class="pln"> dataString </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">root</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'x-data'</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">dataString</span><span class="pun">})`)</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">

    registerListeners</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">walkDOM</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> el </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">el</span><span class="pun">.</span><span class="pln">attributes</span><span class="pun">).</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">attribute </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">attribute</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="str">'@'</span><span class="pun">))</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">

                </span><span class="kwd">let</span><span class="pln"> event </span><span class="pun">=</span><span class="pln"> attribute</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">'@'</span><span class="pun">,</span><span class="pln"> </span><span class="str">''</span><span class="pun">);</span><span class="pln">
                el</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="pln">event</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">eval</span><span class="pun">(`</span><span class="kwd">with</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">attribute</span><span class="pun">.</span><span class="pln">value</span><span class="pun">})</span><span class="pln"> </span><span class="pun">}`)</span><span class="pln">
                </span><span class="pun">})</span><span class="pln">
            </span><span class="pun">})</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">

    observe</span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">var</span><span class="pln"> self </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Proxy</span><span class="pun">(</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">set</span><span class="pun">(</span><span class="pln">target</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                target</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> value

                self</span><span class="pun">.</span><span class="pln">refreshDOM</span><span class="pun">()</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">

    refreshDOM</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">walkDOM</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> el </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">el</span><span class="pun">.</span><span class="pln">attributes</span><span class="pun">).</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">attribute </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">directives</span><span class="pun">).</span><span class="pln">includes</span><span class="pun">(</span><span class="pln">attribute</span><span class="pun">.</span><span class="pln">name</span><span class="pun">))</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">

                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">directives</span><span class="pun">[</span><span class="pln">attribute</span><span class="pun">.</span><span class="pln">name</span><span class="pun">](</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">eval</span><span class="pun">(`</span><span class="kwd">with</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">attribute</span><span class="pun">.</span><span class="pln">value</span><span class="pun">})</span><span class="pln"> </span><span class="pun">}`))</span><span class="pln">
            </span><span class="pun">})</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">

    walkDOM</span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        callback</span><span class="pun">(</span><span class="pln">el</span><span class="pun">)</span><span class="pln">

        el </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">firstElementChild
        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">el</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">walkDOM</span><span class="pun">(</span><span class="pln">el</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln">

            el </span><span class="pun">=</span><span class="pln"> el</span><span class="pun">.</span><span class="pln">nextElementSibling
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span><span class="pln">

window</span><span class="pun">.</span><span class="typ">Alpine</span><span class="pun">.</span><span class="pln">start</span><span class="pun">();</span></pre>

<p>
	ستجد الملفات الخاصة بهذا المقال في المستودع التالي على موقع Github: <a href="https://github.com/SamirAbboud/Alpine-Simple-MVP" rel="external nofollow">إنشاء نموذج <abbr title="Minimum Viable Product | المنتج الفعال القاعدي"><abbr title="Minimum Viable Product | المنتج الفعال القاعدي">MVP</abbr></abbr> مصغر لمكتبة Alpine</a>
</p>

<h2 id="">
	خاتمة
</h2>

<p>
	في الختام يمكن القول أن إطار العمل Alpine.js هو إطار عمل صغير وبسيط سهل التعلم والاستخدام يحتوي على مجموعة من الأدوات تسمح بإضافة تفاعلية على صفحات التطبيق بشكل سلس دون حاجة إلى تعقيدات كبيرة إضافة إلى أنه لا يؤثر على أداء الموقع أو صفحات التطبيق الخاص بك، باختصار إذا كنت تبحث عن إطار عمل سهل الاستخدام وفعّال في نفس الوقت، فإن Alpine.js قد يكون الخيار المثالي الذي يجمع بين البساطة والقوة.
</p>

<p>
	يشكل هذا الإطار نقلة نوعية في تحسين تجربة المستخدم وتسريع تطوير تطبيقات الويب. تعرفنا في هذا المقال على بعض مميزات هذا الإطار واستطعنا من خلال بنائنا للنموذج فهم آلية عمل هذا الإطار وكيفية تحقيقه للتفاعلية والبساطة، وسنتعرف في المقالات القادمة على مميزات أخرى لهذا الإطار من خلال إنشاء بعض الأمثلة البسيطة وإنشاء تطبيق كامل عبر Alpine.js.
</p>

<h2 id="-1">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%B5%D9%81%D8%B1-%D8%AD%D8%AA%D9%89-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81-r2046/" rel="">تعلم لغة جافا سكريبت من الصفر حتى الاحتراف</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-framework/" rel="">تعرف على مفهوم إطار العمل Framework وأهميته في البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AA%D9%89-%D9%86%D8%B3%D8%AA%D8%B9%D9%85%D9%84-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-%D9%84%D9%84%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-javascript-r477/" rel="">متى نستعمل إطار عمل للتطوير باستخدام JavaScript</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A3%D8%B7%D8%B1-%D8%B9%D9%85%D9%84-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1567/" rel="">مقدمة إلى أطر عمل تطوير الويب من طرف العميل</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2214</guid><pubDate>Sat, 06 Jan 2024 12:01:00 +0000</pubDate></item><item><title>&#x641;&#x647;&#x645; &#x646;&#x638;&#x627;&#x645; &#x627;&#x644;&#x646;&#x648;&#x639; &#x641;&#x64A; GraphQL</title><link>https://academy.hsoub.com/programming/javascript/%D9%81%D9%87%D9%85-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D9%86%D9%88%D8%B9-%D9%81%D9%8A-graphql-r2195/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_12/----GraphQL.png.137ff73286dd793199e33dde0ff6c3e1.png" /></p>
<p>
	تُسهّل GraphQL الاتصال بين الواجهة الأمامية لتطبيقك وقاعدة البيانات عبر استعلاماتها التصريحية والموجهة بطلبات العميل، والبنية التي توضح إمكانات هذه الاستعلامات وتفاصيلها هي <a href="https://spec.graphql.org/June2018/#sec-Schema" rel="external nofollow">مخططات GraphQL</a> المحكومة <a href="https://spec.graphql.org/June2018/#sec-Type-System" rel="external nofollow">بنظام النوع</a>، فما هو نظام النوع؟ وكيف يساعدك فهمه على بناء مخططات فعالة تحقق لك الفائدة المرجوة من GraphQL؟ سنعرض ذلك مع بعض الأمثلة التطبيقية على كل نوع بدءًا من الأنواع الخمسة المفردة المبنية مسبقًا built-in scalar، والتعدادات Enums، والقوائم والواجهات Interfaces والأنواع غير الفارغة الغالفة non-null wrapping، ونوع الكائن Object، وأنواع التجريد Abstract والاتحاد Union أيضًا.
</p>

<h2 id="">
	متطلبات العمل
</h2>

<p>
	ستحتاج هذه الأساسيات لتطبيق الأمثلة الموجودة هنا:
</p>

<ul>
	<li>
		الاطلاع على المقال الأول <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-graphql-r2208/" rel="">مقدمة إلى GraphQL</a> لفهم المبادئ الأساسية للتقنية.
	</li>
	<li>
		بيئة عمل تحوي خادم GraphQL، يمكنك تجهيزها بتنفيذ الخطوات الموجودة في مقالنا الثاني <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AE%D8%A7%D8%AF%D9%85-graphql-%D9%81%D9%8A-%D8%A8%D9%8A%D8%A6%D8%A9-nodejs-r2189/" rel="">إعداد خادم GraphQL في بيئة Node.js</a>.
	</li>
</ul>

<h2 id="scalar">
	الأنواع المفردة Scalar
</h2>

<p>
	إذا شبهت استجابة <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8%D8%A9-graphql-%D9%88%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84%D8%A7%D8%AA%D9%87%D8%A7-%D9%81%D9%8A-%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AD%D8%AF%D9%8A%D8%AB%D8%A9-r1208/" rel="">GraphQL</a> بالشجرة متفرعة الأغصان فستكون البيانات المفردة هي الأوراق في نهاية كل غصن، ففي نهاية الأمر تتحلل جميع البيانات في مخطط GraphQL مهما بلغ تعقيدها وتداخلها إلى <a href="https://spec.graphql.org/June2018/#sec-Scalars" rel="external nofollow">بيانات مفردة</a>، وللبيانات المفردة خمسة أنواع:
</p>

<h3 id="int">
	نوع العدد الصحيح Int
</h3>

<p>
	<a href="https://spec.graphql.org/June2018/#sec-Int" rel="external nofollow"><code>Int</code></a> هو نوع عدد صحيح لا يحتوي فاصلة عشرية، ومُؤشّر بإشارة موجب أو سالب، ويتكون من 32 بت، لذا تتراوح قيمته بين "2,147,483,647-" و "2,147,483,647"، والعدد الصحيح هو واحد من نوعين فقط لتمثيل الأعداد في GraphQL.
</p>

<h3 id="float">
	نوع العدد العشري Float
</h3>

<p>
	<a href="https://spec.graphql.org/June2018/#sec-Float" rel="external nofollow"><code>Float</code></a> هو نوع عدد عشري ثنائي الدقة، مثل 1.2، ومُؤشّر بإشارة موجب أو سالب، وهو النوع المفرد الثاني لتمثيل الأعداد في GraphQL.
</p>

<h3 id="string">
	نوع السلسلة النصية String
</h3>

<p>
	<a href="https://spec.graphql.org/June2018/#sec-String" rel="external nofollow"><code>String</code></a> هو نوع سلسلة محارف بترميز <a href="https://academy.hsoub.com/questions/11986-%D9%85%D8%B9%D9%86%D9%89-utf8/" rel=""><code>UTF-8</code></a> تُستخدم لكتابة النصوص والأعداد الكبيرة جدًا، وتُعد السلاسل النصية أكثر الأنواع المفردة استخدامًا.
</p>

<h3 id="boolean">
	النوع البولياني Boolean
</h3>

<p>
	يحمل النوع البولياني <a href="https://www.digitalocean.com/community/conceptual-articles/understanding-the-graphql-type-system" rel="external nofollow"><code>Boolean</code></a> إما قيمة صحيحة <code>true</code> أو خاطئة <code>false</code>.
</p>

<h3 id="id">
	نوع الرقم التعريفي ID
</h3>

<p>
	<a href="https://spec.graphql.org/June2018/#sec-ID" rel="external nofollow"><code>ID</code></a> هو رقم تعريفي فريد، يُمثّل دائمًا بصيغة سلسلة نصية حتى لو تضمن أرقامًا، ويُولّد غالبًا بواسطة خوارزميات <a href="https://developer.mozilla.org/en-US/docs/Glossary/UUID" rel="external nofollow">المُعرّف العالمي الفريد Universally Unique Identifier</a> أو اختصارًا UUID.
</p>

<h3 id="-1">
	أنواع مفردة مخصصة
</h3>

<p>
	تغطي الأنواع المفردة الخمسة السابقة معظم حالات الاستخدام، لكنك قد تحتاج أنواعًا أخرى تناسب طبيعة تطبيقك، مثل الوقت <code>Time</code>، والتاريخ <code>Date</code>، وعناوين <code>url</code>، والتي يمكنك تعريفها باستعمال الكلمة المفتاحية <code>scalar</code>، وسيعتمد الخادم عندها هذه الأنواع معيارًا للتحقق من صحة بياناتك المدخلة ومطابقتها لمواصفات النوع المخصص الذي تنتمي إليه. إليك مثالًا عن تعريف نوع التاريخ <code>Date</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_7" style=""><span class="pln">scalar </span><span class="typ">Date</span></pre>

<p>
	يستخدم خادم GraphQL الوحدة البرمجية <a href="https://graphql.org/graphql-js/type/" rel="external nofollow">GraphQLScalarType</a> للتعامل مع الأنواع الجديدة المُضافة.
</p>

<h2 id="enum">
	نوع التعداد Enum
</h2>

<p>
	يصف <a href="https://spec.graphql.org/June2018/#sec-Enums" rel="external nofollow">التعداد</a> مجموعةً من القيم المحتملة للعنصر.
</p>

<p>
	لو طبقت الأمر على اللعبة التي استخدمناها مثالًا في مقالات السلسلة، ستجد أنك تحتاج نوع التعداد عند تعريف وظائف شخصيات اللعبة <code>Job</code>، وأنواعهم <code>Species</code>، وأسلحتهم وما إلى ذلك؛ فلكل شخصية قيم محددة لا ينبغي أن يقبل النظام غيرها. يُعرّف نوع التعداد باستعمال الكلمة المفتاحية <code>enum</code>، وتكتب التعدادات ضمنه بالحروف الإنجليزية الكبيرة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_9" style=""><span class="str">"The job class of the character."</span><span class="pln">
</span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">Job</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  FIGHTER
  WIZARD
</span><span class="pun">}</span><span class="pln">

</span><span class="str">"The species or ancestry of the character."</span><span class="pln">
</span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">Species</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  HUMAN
  ELF
  DWARF
</span><span class="pun">}</span></pre>

<p>
	تضمن بهذه الطريقة أن وظيفة الشخصية <code>Job</code> ستكون إما مقاتل <code>FIGHTER</code> أو ساحر <code>WIZARD</code> فقط، ولن يقبل <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">الخادم</a> أي كلمة أخرى مهما كانت؛ أما لو عرّفت وظيفة الشخصية على أنها سلسلة نصية عادية <code>String</code>، فستكون جميع الكلمات سيان عند الخادم وسيقبل أي مجموعة محارف تُعطى له.
</p>

<p>
	تفيدك التعدادات أيضًا في تمرير القيم الوسيطة، إذ يمكنك مثلًا تعريف تعداد <code>enum</code> لتحديد إذا كان سلاح الشخصية يُحمَل بيد واحدة مثل السيف أم أنه ثقيل مثل الفأس ويحتاج لكلتا اليدين، سيساعدك هذا التعداد على التحكم بتجهيز الشخصية بسلاح واحد أو بسلاحين، لنسمي التعداد اليد <code>Hand</code>، ونعرّفه بالتعليمات التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_12" style=""><span class="kwd">enum</span><span class="pln"> </span><span class="typ">Hand</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  SINGLE
  DOUBLE
</span><span class="pun">}</span><span class="pln">

</span><span class="str">"A valiant weapon wielded by a fighter."</span><span class="pln">
type </span><span class="typ">Weapon</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">!</span><span class="pln">
  attack</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Int</span><span class="pln">
  range</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Int</span><span class="pln">
  hand</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Hand</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

type </span><span class="typ">Query</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  weapons</span><span class="pun">(</span><span class="pln">hand</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Hand</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> SINGLE</span><span class="pun">):</span><span class="pln"> </span><span class="pun">[</span><span class="typ">Weapon</span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	صُرّح عن التعداد <code>Hand</code> بحالتين لاستعمال اليد، مفردة <code>SINGLE</code>، ومزدوجة <code>DOUBLE</code>، أما الوسيط المسند إلى الحقل <code>weapons</code> في الاستعلام فيحمل القيمة الافتراضية <code>SINGLE</code>، وهي القيمة التي يأخذها في حال لم تمنحه قيمة مغايرة.
</p>

<h2 id="nonnull">
	النوع غير الفارغ Non-Null
</h2>

<p>
	قد تستغرب عدم وجود النوع <code>null</code> أو <code>undefined</code> بين أنواع GraphQL المفردة رغم أنه يُعدّ نوعًا شائعًا في معظم لغات البرمجة، ويرجع السبب في ذلك إلى أن جميع أنواع GraphQL تقبل القيمة Null افتراضيًا وفي حال أردت تغيير الأمر عليك استخدام إشارة التعجب مع اسم النوع.
</p>

<p>
	يُعرّف النوع <a href="https://spec.graphql.org/June2018/#sec-Type-System.Non-Null" rel="external nofollow">غير الفارغ Non-Null</a> في GraphQL بأنه مُعدِّل للأنواع الأخرى، فمثلًا الحقل <code>String</code> هو حقل اختياري قد يحمل قيمة أو لا، أما الحقل من النوع <code>!String</code> فهو إجباري أي لا يجب أن يكون فارغًا.
</p>

<h2 id="list">
	نوع القائمة List
</h2>

<p>
	نوع <a href="https://spec.graphql.org/June2018/#sec-Type-System.List" rel="external nofollow">القائمة</a> هو أيضًا من الأنواع المُعدِّلة للأنواع الأخرى، فأي نوع يوضع بين قوسين مربعين <code>[]</code> يتحول لقائمة.
</p>

<p>
	على سبيل المثال يُعرّف النوع <code>[Int]</code> قائمةً من نوع الأعداد الصحيحة <code>Int</code> والنوع <code>[String]</code> قائمةً من السلاسل النصية <code>String</code> وقِس على ذلك، ويمكنك استخدام القائمة مع إشارة التعجب لتحصل على نوع غير فارغ ومُعرّف على أنه قائمة مثل <code>![String]</code>.
</p>

<h2 id="object">
	نوع الكائن Object
</h2>

<p>
	شبهنا الأنواع المفردة بأوراق الشجرة في بداية المقال، وتبعًا لهذا التشبيه تكون الكائنات هي الأغصان، وهي معظم ما سنكتبه في مخطط GraphQL.
</p>

<p>
	يبدأ تعريف <a href="https://spec.graphql.org/June2018/#sec-Objects" rel="external nofollow">الكائن</a> بالكلمة المفتاحية <code>type</code>، ويحتوي كل كائن على حقل واحد على الأقل. تُسمى الحقول بالمفاتيح وبجانب كل حقل تجد نوع القيمة التي يقبلها. لا يجوز أن تبدأ أسماء الحقول برمز الشرطتين السفليتين <code>__</code>، فهو مخصص لنظام الاستقراء.
</p>

<p>
	لو أعطينا مثالًا في سياق أمثلتنا السابقة عن اللعبة، فيمكنك إنشاء كائن يمثل المقاتلين <code>Fighter</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_14" style=""><span class="str">"A hero with direct combat ability and strength."</span><span class="pln">
type </span><span class="typ">Fighter</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> ID</span><span class="pun">!</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">!</span><span class="pln">
  level</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Int</span><span class="pln">
  active</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Boolean</span><span class="pun">!</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمتلك هذا الكائن أربعة حقول:
</p>

<ul>
	<li>
		<code>id</code> رقم تعريفي من نوع <code>ID</code> غير فارغ.
	</li>
	<li>
		<code>name</code> سلسلة نصية <code>String</code> غير فارغة.
	</li>
	<li>
		<code>level</code> عدد صحيح <code>Int</code>.
	</li>
	<li>
		<code>active</code> قيمة منطقية <code>Boolean</code> غير فارغة.
	</li>
</ul>

<p>
	ونود الإشارة هنا إلى قدرتك على كتابة تعليق قبل تعريف الكائن مباشرةً بين علامتي اقتباس، مثل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_17" style=""><span class="str">"A hero with direct combat ability and strength."</span></pre>

<p>
	وسيظهر تعليقك بمثابة الوصف للكائن.
</p>

<p>
	قد تكون حقول الكائن بيانات مفردة كما في مثالنا السابق أو كائنات أخرى. ألقِ نظرةً على المثال أدناه، إذ عرّفنا في البداية كائنًا من نوع السلاح <code>Weapon</code> يتضمن أسماء الأسلحة وطبيعة هجومها ومدى تأثيرها، ثم أضفنا السلاح <code>weapon</code> على أنه أحد حقول كائن المقاتل <code>Fighter</code> وهو <code>weapon</code>. يمكن لمخطط GraphQL أن يُضبط بحيث يعالج الحقل <code>weapon</code> الكائن <code>Weapon</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_19" style=""><span class="str">"A valiant weapon wielded by a fighter."</span><span class="pln">
type </span><span class="typ">Weapon</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">!</span><span class="pln">
  attack</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Int</span><span class="pln">
  range</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Int</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="str">"A hero with direct combat ability and strength."</span><span class="pln">
type </span><span class="typ">Fighter</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> ID</span><span class="pun">!</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">!</span><span class="pln">
  level</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Int</span><span class="pln">
  active</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Boolean</span><span class="pun">!</span><span class="pln">
  weapon</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Weapon</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن أن تتداخل الكائنات ببعضها ويشترك أكثر من كائن بالحقل نفسه.
</p>

<h3 id="-2">
	أنواع عمليات الجذر
</h3>

<p>
	<a href="https://spec.graphql.org/June2018/#sec-Root-Operation-Types" rel="external nofollow">عمليات الجذر</a> هي أنواع خاصة من الكائنات تنطبق عليها جميع قواعد الكائنات، تمثل جذور مخطط GraphQL وتسمى نقاط دخول entrypoints، ولها ثلاثة أنواع هي الاستعلامات والطفرات والاشتراكات.
</p>

<p>
	تُعرّف هذه العمليات ضمن كائن الجذر <code>schema</code> في مخطط GraphQL، والمميز بالكلمة المفتاحية <code>schema</code>. ألقِ نظرةً على التعليمات التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_21" style=""><span class="pln">schema </span><span class="pun">{</span><span class="pln">
  query</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Query</span><span class="pln">
  mutation</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Mutation</span><span class="pln">
  subscription</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Subscription</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنبدأ بنوع الاستعلام Query type، وهو عملية أساسية لا غنى عنها في أي مخطط GraphQL، ويمثّل عملية قراءة، ويقابل <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-http-%D9%81%D9%8A-nodejs-r1868/" rel="">الطلب <code>GET</code></a> في واجهة REST <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>. ألقِ نظرةً على تعريف استعلام الجذر <code>Query</code> للعبة نفسها، إذ يُرجِع هذا الاستعلام قائمة بالمقاتلين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_23" style=""><span class="pln">type </span><span class="typ">Query</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  fighters</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="typ">Fighter</span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أما الطفرات فتمثل طلبات الكتابة لأنها تعدل على المخطط، فهي تشبه طلبات <code>PUT</code> و <code>DELETE</code> و <code>POST</code> في REST <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>. يبين المثال أدناه الطفرة <code>Mutation</code> التي تستخدم الوسيط <code>input</code> لإضافة مقاتل <code>addFighter</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_27" style=""><span class="pln">type </span><span class="typ">Mutation</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  addFighter</span><span class="pun">(</span><span class="pln">input</span><span class="pun">:</span><span class="pln"> </span><span class="typ">FighterInput</span><span class="pun">):</span><span class="pln"> </span><span class="typ">Fighter</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عملية الجذر الأخيرة هي الاشتراكات Subscription، التي تفيدك في حالات تدفق الأحداث بين الخادم والعميل، وتعمل بتوافق تام مع <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D9%82%D9%86%D9%8A%D8%A9-websocket-r660/" rel="">تقنية WebSocket</a>.
</p>

<p>
	بالعودة للعبة، يمكنك استخدام الاشتراكات لتمثيل الاصطدامات العشوائية في المعارك مثلًا على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_29" style=""><span class="pln">type </span><span class="typ">Subscription</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  randomBattle</span><span class="pun">(</span><span class="pln">enemy</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Enemy</span><span class="pun">):</span><span class="pln"> </span><span class="typ">BattleResult</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3 id="fieldarguments">
	وسطاء الحقول Field Arguments
</h3>

<p>
	حقول الكائن في GraphQL هي دوال تقليدية ترجِِع قيمًا وتقبل متغيراتٍ وسيطة مثلها مثل الدوال الأخرى، وتنتمي <a href="https://spec.graphql.org/June2018/#sec-Field-Arguments" rel="external nofollow">وسطاء الحقل</a> إلى أي نوع غير فارغ من أنواع GraphQL باستثناء الكائنات، وتُعرّف بكتابة اسم المتغير يليه نوعه.
</p>

<p>
	ألقِ نظرةً على المثال التالي لترشيح الكائن <code>Fighter</code> باستخدام الحقل <code>id</code>، ولاحظ إشارة التعجب بعد النوع للدلالة على عدم قبول قيم <code>ID</code> الفارغة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_31" style=""><span class="pln">type </span><span class="typ">Query</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  fighter</span><span class="pun">(</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> ID</span><span class="pun">!):</span><span class="pln"> </span><span class="typ">Fighter</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تلعب الوسطاء في هذا المثال دورًا في ترشيح كائن المقاتل <code>Fighter</code> بحسب الرقم التعريفي، فتمكّنك من جلب عنصر محدد من مخزن البيانات، وتستطيع استخدامها لأي استعلامات أخرى تريدها.
</p>

<h2 id="interface">
	نوع الواجهة Interface
</h2>

<p>
	تشبه بنية <a href="https://spec.graphql.org/June2018/#sec-Interfaces" rel="external nofollow">نوع الواجهة</a> بنية الكائنات، فهي تتكون من عدة حقول لكل منها اسم ونوع، والغاية منها وضع نموذج مشترك يمكن تطبيقه على مجموعة كائنات تمتلك حقولًا مشتركة.
</p>

<p>
	أنشأنا في الفقرات السابقة كائن المقاتل <code>Fighter</code> وهو يشترك في بعض حقوله مع كائنات أخرى تلعب أدوارًا في اللعبة، مثل المعالجين <code>Healer</code> والسحرة <code>Wizard</code> وغيرهم. يمكنك في هذه الحالة إنشاء واجهة تتضمن الحقول المشتركة بين جميع هذه الشخصيات، ثم إنشاء كائنات منفصلة لكل شخصية تكون تطبيقًا للواجهة. ألقِ نظرةً على المثال التالي لتوضيح الأمر.
</p>

<p>
	أنشئ في البداية واجهة تسمى <code>BaseCharacter</code> تبدأ بالكلمة المفتاحية <code>interface</code> وتتضمن كل الحقول المشتركة بين الشخصيات، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_33" style=""><span class="str">"A hero on a quest."</span><span class="pln">
</span><span class="kwd">interface</span><span class="pln"> </span><span class="typ">BaseCharacter</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> ID</span><span class="pun">!</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">!</span><span class="pln">
  level</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Int</span><span class="pun">!</span><span class="pln">
  species</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Species</span><span class="pln">
  job</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Job</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لكل شخصية في اللعبة رقم تعريفي خاص <code>id</code> واسم <code>name</code> ومستوى <code>level</code> ونوع <code>species</code> وعمل <code>job</code>.
</p>

<p>
	خذ مثلًا نوع المقاتل <code>Fighter</code> ونوع الساحر <code>Wizard</code> لدى كل منهم جميع الحقول الموجودة في الواجهة <code>BaseCharacter</code> مع بعض الاختلاف؛ فالمقاتل يستعمل الأسلحة <code>Weapon</code>؛ والساحر يستعمل التعويذات <code>Spell</code>. يمكنك إذًا تطبيق الواجهة لتسهيل تعريف النوعين، وذلك باستخدام الكلمة المفتاحية <code>implements</code>، وفق التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_35" style=""><span class="str">"A hero with direct combat ability and strength."</span><span class="pln">
type </span><span class="typ">Fighter</span><span class="pln"> </span><span class="kwd">implements</span><span class="pln"> </span><span class="typ">BaseCharacter</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> ID</span><span class="pun">!</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">!</span><span class="pln">
  level</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Int</span><span class="pun">!</span><span class="pln">
  species</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Species</span><span class="pln">
  job</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Job</span><span class="pun">!</span><span class="pln">
  weapon</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Weapon</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="str">"A hero with a variety of magical powers."</span><span class="pln">
type </span><span class="typ">Wizard</span><span class="pln"> </span><span class="kwd">implements</span><span class="pln"> </span><span class="typ">BaseCharacter</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> ID</span><span class="pun">!</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">!</span><span class="pln">
  level</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Int</span><span class="pun">!</span><span class="pln">
  species</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Species</span><span class="pln">
  job</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Job</span><span class="pun">!</span><span class="pln">
  spells</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="typ">Spell</span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تذكر أن شرط تطبيق الواجهة على كائن معين هو امتلاك الكائن لجميع حقول الواجهة دون استثناء.
</p>

<h2 id="union">
	نوع الاتحاد Union
</h2>

<p>
	يمثل <a href="https://spec.graphql.org/June2018/#sec-Unions" rel="external nofollow">نوع الاتحاد</a> مجموعة كائنات تصلح لأن تكون استجابة لاستعلام واحد.
</p>

<p>
	لننشئ مثلًا اتحادًا لشخصيات اللعبة <code>Character</code> تتضمن كافة كائنات الشخصيات، وهي في حالتنا كائنات المقاتل <code>Fighter</code> والساحر <code>Wizard</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1341_37" style=""><span class="kwd">union</span><span class="pln"> </span><span class="typ">Character</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Wizard</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Fighter</span></pre>

<p>
	يبدأ تعريف الاتحاد بالكلمة المفتاحية <code>Union</code>، والتي تكون مدخلاتها إما كائنات أو واجهات فهي لا تقبل الأنواع المفردة. ترمز إشارة اليساوي <code>=</code> ضمن التعريف إلى إسناد القيمة، أما الخط الرأسي <code>|</code> فيكافئ عبارة <code>OR</code> المنطقية.
</p>

<p>
	الآن، إذا رغبت بالاستعلام عن شخصيات اللعبة فيمكنك استخدام الاتحاد <code>Character</code> ليستجيب الخادم بقائمة تضم جميع الكائنات من نوع مقاتل <code>Fighter</code> أو ساحر <code>Wizard</code>.
</p>

<h2 id="-3">
	الخاتمة
</h2>

<p>
	تعرّفنا في هذا المقال على أنواع GraphQL المختلفة، شبهنا المخطط بالشجرة فكانت الأنواع المفردة بمثابة الأوراق التي ينتهي إليها كل شيء، فهي أنواعٌ تساهم بتشكيل الأنواع الأخرى، ولها خمسة أنواع أساسية هي <code>Int</code> و <code>Float</code> و <code>String</code> و <code>Boolean</code> و <code>ID</code> ويمكنك إنشاء أنواعك الخاصة، ثم عرضنا نوع التعداد الذي يمنحك تحكمًا أكبر في استجابة الخادم فتزوده بمجموعة محددة من القيم الصالحة، وبعدها اطلعنا على مُعدِّلات الأنواع أي القائمة والقيم غير الفارغة التي تُغيّر طبيعة الأنواع الأخرى، وتوسعنا في الكائنات لأنها عماد مخططات GraphQL فهي أشبه بأغصان الشجرة بما فيها من كائنات جوهرية تتمثل في عمليات الجذر أي الاستعلامات والطفرات والاشتراكات، ولا ننسَ الواجهات والروابط التي تُسهّل علينا التعامل مع الكائنات ذات الخصائص المشتركة.
</p>

<p>
	لديك الآن أساسٌ نظري جيد ننصحك ببناء خادمك الخاص بمساعدة مقال <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AE%D8%A7%D8%AF%D9%85-graphql-%D9%81%D9%8A-%D8%A8%D9%8A%D8%A6%D8%A9-nodejs-r2189/" rel="">إعداد خادم GraphQL في بيئة Node.js</a> والتدرب عمليًّا على تطبيق الأنواع لحين إتقانها.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/conceptual-articles/understanding-the-graphql-type-system" rel="external nofollow">Understanding the GraphQL Type System</a> لصاحبته Tania Rascia.
</p>

<h2 id="-4">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AE%D8%A7%D8%AF%D9%85-graphql-%D9%81%D9%8A-%D8%A8%D9%8A%D8%A6%D8%A9-nodejs-r2189/" rel="">إعداد خادم GraphQL في بيئة Node.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1726/" rel="">دليلك الشامل إلى أنواع البيانات</a><span style="display: none;"> </span>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-nodejs-r1463/" rel="">مقدمة إلى Node.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A3%D9%88%D9%84-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC-%D9%81%D9%8A-%D8%A8%D9%8A%D8%A6%D8%A9-nodejs-%D9%88%D8%AA%D9%86%D9%81%D9%8A%D8%B0%D9%87-r1711/" rel="">كتابة أول برنامج في بيئة Node.js وتنفيذه</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8%D8%A9-graphql-%D9%88%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84%D8%A7%D8%AA%D9%87%D8%A7-%D9%81%D9%8A-%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AD%D8%AF%D9%8A%D8%AB%D8%A9-r1208/" rel="">مدخل إلى المكتبة GraphQL واستعمالاتها في بناء تطبيقات الويب الحديثة</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/32-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-nodejs/" rel="">البرمجة باستخدام Node.js </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2195</guid><pubDate>Wed, 13 Dec 2023 16:04:00 +0000</pubDate></item><item><title>&#x645;&#x628;&#x627;&#x62F;&#x626; &#x643;&#x62A;&#x627;&#x628;&#x629; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A; &#x645;&#x62A;&#x633;&#x642;&#x629; &#x648;&#x645;&#x641;&#x647;&#x648;&#x645;&#x629;</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D8%A8%D8%A7%D8%AF%D8%A6-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D8%AA%D8%B3%D9%82%D8%A9-%D9%88%D9%85%D9%81%D9%87%D9%88%D9%85%D8%A9-r2178/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_11/----.png.45bb6775832a6ad1bf51962b1d0a63bb.png" /></p>
<p>
	يجب أن تبدو الشيفرات البرمجية أينما وجدت كما لو أن مبرمجًا واحدًا كتبها، بغض النظر عن عدد من ساهم فيها.
</p>

<p>
	توضّح القائمة التالية بعض الإرشادات المُستخدمة في كل الشيفرات البرمجية.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		"الجدل في الأسلوب لا يؤدي إلى شيء. يجب أن يكون هناك دليلاً للأسلوب (style guide)، ويجب اتباعه" _ريبيكا مورفي
	</p>

	<p>
		"أحد العوامل التي تجعلك مديرًا جيدًا للمشاريع الناجحة هو أنه عليك أن تفهم أن كتابة التعليمات البرمجية بأسلوبك الخاص دائمًا هي ممارسة سيئة. إذا كان الآلاف من الناس يستخدمون شيفراتك، فاكتبها بأقصى قدر من الوضوح، بدلاً من محاولة أن تبدو ذكيًا في أسلوبك في الكتابة." _إيدان جازيت
	</p>
</blockquote>
<iframe allowfullscreen="" data-controller="core.front.core.autosizeiframe" data-embedauthorid="3889" data-embedcontent="" src="https://academy.hsoub.com/files/27-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA/?do=embed" style="margin: auto;"></iframe>

<h2 id="">
	مقدمة
</h2>

<p>
	توضّح الأقسام التالية دليل أسلوب معتدل reasonable لتطوير <a href="https://academy.hsoub.com/programming/javascript/" rel="">جافا سكريبت Javascript</a> الحديثة وليس المقصود منها أن تكون مواصفات صارمة.
</p>

<p>
	أهم ما يمكن تعلمه هو <strong>قانون اتساق نمط الشيفرات البرمجية</strong>، فكل ما تختاره أسلوبًا لمشروعك يجب أن يعد قانونًا. اتّخذ هذا المقال مرجعًا لالتزام مشروعك بتناسق نمط الشيفرات، وسهولة قراءتها، وقابليتها للصيانة.
</p>

<h2 id="-1">
	بيان الأسلوب الاصطلاحي
</h2>

<h3 id="-2">
	المسافة الفارغة
</h3>

<p>
	هذه بعض النصائح الممكن الاستفادة منها بشأن المسافات الفارغة:
</p>

<ul>
	<li>
		لا تخلط بين المسافات spaces ومسافة tab إطلاقًا.
	</li>
	<li>
		عند بدء المشروع، وقبل أن تكتب أي شيفرة برمجية، اختر إما المسافات أو مسافات tab، وليس كليهما. اتّبع هذا على طول المشروع واجعله <strong>قانونًا</strong>.
	</li>
	<li>
		لزيادة جودة القراءة، يُوصى دائمًا بتعيين حجم المسافة البادئة indent لمحررك على حرفين، وهذا يعني مسافتين.
	</li>
	<li>
		إذا كان محررك يدعم إعداد "إظهار العناصر غير المرئية"، فيُنصح بتشغيله دائمًا؛ ففوائده هي:
	</li>
	<li>
		فرض الاتساق consistency.
	</li>
	<li>
		إزالة المسافة الفارغة في نهاية السطر.
	</li>
	<li>
		إزالة الأسطر الفارغة.
	</li>
	<li>
		تسهيل قراءة الإيداعات Commits والاختلافات diffs، والتي تأتي غالبًا أثناء معالجة إدارة النسخ version control.
	</li>
	<li>
		استخدم <a href="http://editorconfig.org" rel="external nofollow">Editorconfig</a> متى ما أمكن ذلك، فهو يدعم معظم محررات التطوير، ويتعامل مع معظم إعدادات المسافات الفارغة.
	</li>
</ul>

<h3 id="beautifulsyntax">
	الصيغ الجميلة Beautiful Syntax
</h3>

<h4 id="linebreaks">
	أولًا: الأقواس الهلالية <code>()</code> والمعقوصة <code>{}</code> والمعقوفة <code>[]</code>، وفواصل الأسطر Linebreaks
</h4>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_7" style=""><span class="com">// مسافات فراغ، وأقواس وأسطر متعددة if و else و for و while و try سيكون لتعليمات </span><span class="pln">
</span><span class="com">// هذا سيحسّن جودة القراءة</span><span class="pln">

</span><span class="com">// 2.A.1.1</span><span class="pln">
</span><span class="com">// أمثلة على بناء جملة محشورة جدًأ</span><span class="pln">

</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">condition</span><span class="pun">)</span><span class="pln"> doSomething</span><span class="pun">();</span><span class="pln">

</span><span class="kwd">while</span><span class="pun">(</span><span class="pln">condition</span><span class="pun">)</span><span class="pln"> iterating</span><span class="pun">++;</span><span class="pln">

</span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;</span><span class="lit">100</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++)</span><span class="pln"> someIterativeFn</span><span class="pun">();</span><span class="pln">


</span><span class="com">// 2.A.1.1</span><span class="pln">
</span><span class="com">// استخدم المسافة الفارغة لتعزيز جودة القراءة</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> condition </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> condition </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="kwd">var</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

  </span><span class="com">// الأفضل</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> i</span><span class="pun">,</span><span class="pln">
  length </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">//  أو</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  length </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> prop</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> prop in object </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span><span class="pln">


</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span></pre>

<h4 id="assignmentsdeclarations">
	ثانيًا: الإسنادات Assignments والتصريحات Declarations والدوال
</h4>

<p>
	مثل الدالة المسمّاة Named Function، والتعبير Expression والباني Constructor
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_9" style=""><span class="com">// 2.B.1.1</span><span class="pln">
</span><span class="com">// المتغيرات</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> foo </span><span class="pun">=</span><span class="pln"> </span><span class="str">"bar"</span><span class="pun">,</span><span class="pln">
  num </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  undef</span><span class="pun">;</span><span class="pln">

</span><span class="com">// القيم المجردة:</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> array </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
  object </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln">


</span><span class="com">// 2.B.1.2</span><span class="pln">
</span><span class="com">// واحد لكل متغير `var` واحد فقط لكل نطاق (دالة) أو `var` استخدام</span><span class="pln">
</span><span class="com">// يعزز جودة القراءة ويحافظ على قائمة التصريحات خالية من الفوضى.</span><span class="pln">
</span><span class="com">// واحد التحكم أكثر في إصداراتك `var` يمكنك باستخدام </span><span class="pln">
</span><span class="com">// ويسهل إعادة ترتيب السطور</span><span class="pln">
</span><span class="com">// واحد لكل نطاق اكتشاف المتغيرات غير المصرّحة `var` يسهّل استخدام </span><span class="pln">
</span><span class="com">// والتي قد تصبح ضمنًا متغيرات عامة</span><span class="pln">
</span><span class="com">// اختر الأفضل لمشروعك ولا تخلط بينهما أبدًا.</span><span class="pln">

</span><span class="com">// سيء</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> foo </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
  bar </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> qux</span><span class="pun">;</span><span class="pln">


</span><span class="com">// جيد</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> foo </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> bar </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> qux</span><span class="pun">;</span><span class="pln">

</span><span class="com">// أو</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> foo </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
  bar </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
  qux</span><span class="pun">;</span><span class="pln">

</span><span class="com">//  أو</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> </span><span class="com">// التعليق على هذه المتغيرات</span><span class="pln">
foo </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
bar </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
quux</span><span class="pun">;</span><span class="pln">

</span><span class="com">// 2.B.1.3</span><span class="pln">
</span><span class="com">// دائمًا في بداية النطاق (الدالة) التي تتعامل معها var يجب أن تكون تعليمات </span><span class="pln">



</span><span class="com">// سيء</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> foo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

</span><span class="com">// بعض التعليمات البرمجية هنا</span><span class="pln">

  </span><span class="kwd">var</span><span class="pln"> bar </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
    qux</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">


</span><span class="com">// جيد</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> foo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> bar </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
    qux</span><span class="pun">;</span><span class="pln">

</span><span class="com">// كل التعليمات البرمجية بعد التصريح عن المتغيرات</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// 2.B.1.4</span><span class="pln">
</span><span class="com">//‏أيضًا في بداية النطاق ECMAScript 6  من  const و let يجب أن يكون </span><span class="pln">

</span><span class="com">// سيء</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> foo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> foo</span><span class="pun">,</span><span class="pln">
    bar</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> condition </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    bar </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
 </span><span class="pun">}</span><span class="pln">

 </span><span class="com">// جيد</span><span class="pln">
 </span><span class="kwd">function</span><span class="pln"> foo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> foo</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> condition </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> bar </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">

</span><span class="com">// تعليمات برمجية</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أما الدالة المُسماة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_11" style=""><span class="com">// 2.B.2.1</span><span class="pln">
</span><span class="com">// تصريح الدالة المسماة</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> foo</span><span class="pun">(</span><span class="pln"> arg1</span><span class="pun">,</span><span class="pln"> argN </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

</span><span class="pun">}</span><span class="pln">


</span><span class="com">// الاستخدام</span><span class="pln">
foo</span><span class="pun">(</span><span class="pln"> arg1</span><span class="pun">,</span><span class="pln"> argN </span><span class="pun">);</span><span class="pln">


</span><span class="com">// 2.B.2.2</span><span class="pln">
</span><span class="com">// تصريح الدالة المسماة</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> square</span><span class="pun">(</span><span class="pln"> number </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> number </span><span class="pun">*</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">


</span><span class="com">// الاستخدام</span><span class="pln">
square</span><span class="pun">(</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

</span><span class="com">// أسلوب التمرير المتتالي عن طريق تمرير دالة رد نداء ‪‫callback</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> square</span><span class="pun">(</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> callback </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  callback</span><span class="pun">(</span><span class="pln"> number </span><span class="pun">*</span><span class="pln"> number </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

square</span><span class="pun">(</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> square </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// تعليمات برمجية داخل دالة رد النداء </span><span class="pln">
</span><span class="pun">});</span><span class="pln">


</span><span class="com">// 2.B.2.3</span><span class="pln">
</span><span class="com">// تعبير الدالة</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> square </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> number </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// إرجاع شيء ذي قيمة وذي صلة</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> number </span><span class="pun">*</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// تعبير الدالة مع المعرّف</span><span class="pln">
</span><span class="com">//  ميزة هذه الطريقة هو أنها قادرة على استدعاء نفسها، وتقدر أن تتبع</span><span class="pln">
</span><span class="com">// المعرّف في تعقبات المكدس</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> factorial </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> factorial</span><span class="pun">(</span><span class="pln"> number </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> number </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> number </span><span class="pun">*</span><span class="pln"> factorial</span><span class="pun">(</span><span class="pln"> number </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">


</span><span class="com">// 2.B.2.4</span><span class="pln">
</span><span class="com">// تصريح الباني </span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">FooBar</span><span class="pun">(</span><span class="pln"> options </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">options </span><span class="pun">=</span><span class="pln"> options</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// الاستخدام</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> fooBar </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FooBar</span><span class="pun">({</span><span class="pln"> a</span><span class="pun">:</span><span class="pln"> </span><span class="str">"alpha"</span><span class="pln"> </span><span class="pun">});</span><span class="pln">

fooBar</span><span class="pun">.</span><span class="pln">options</span><span class="pun">;</span><span class="pln">
</span><span class="com">// { a: "alpha" }</span></pre>

<h4 id="exceptions">
	ثالثًا: الاستثناءات Exceptions وبعض التفاصيل
</h4>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_13" style=""><span class="com">// 2.C.1.1</span><span class="pln">
</span><span class="com">// الدوال مع رد النداء</span><span class="pln">
foo</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// لاحظ عدم وجود مسافة إضافية بين القوس الأول</span><span class="pln">
  </span><span class="com">// "function" لاستدعاء دالة التنفيذ وكلمة‎‏‎</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="com">// الدالة تقبل تمرير مصفوفة دون فراغ</span><span class="pln">
foo</span><span class="pun">([</span><span class="pln"> </span><span class="str">"alpha"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"beta"</span><span class="pln"> </span><span class="pun">]);</span><span class="pln">

</span><span class="com">// 2.C.1.2</span><span class="pln">
</span><span class="com">// الدالة تقبل تمرير كائن دون فراغ</span><span class="pln">
foo</span><span class="pun">({</span><span class="pln">
  a</span><span class="pun">:</span><span class="pln"> </span><span class="str">"alpha"</span><span class="pun">,</span><span class="pln">
  b</span><span class="pun">:</span><span class="pln"> </span><span class="str">"beta"</span><span class="pln">
</span><span class="pun">});</span><span class="pln">


</span><span class="com">// تمرير سلسلة نصية دون فراغ</span><span class="pln">

foo</span><span class="pun">(</span><span class="str">"bar"</span><span class="pun">);</span><span class="pln">

</span><span class="com">// أقواس التعبير، دون فراغ</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">!(</span><span class="str">"foo"</span><span class="pln"> in obj</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  obj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">bar </span><span class="pun">||</span><span class="pln"> defaults</span><span class="pun">).</span><span class="pln">baz</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h4 id="-3">
	رابعًا: يفوز الاتساق دائمًا
</h4>

<p>
	أوصينا أعلاه بقواعد المسافات الفارغة لغرض أبسط وأسمى ألا وهو الاتساق. تجدر الملاحظة أن تفضيلات التنسيق، مثل "المسافة الفارغة الداخلية" ليست إلا اختيارية، ولكن يجب الالتزام بنمط واحد فقط في كل المشروع.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_15" style=""><span class="com">// 2.D.1.1</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">condition</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// تعليمات برمجية</span><span class="pln">

</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">condition</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// تعليمات برمجية</span><span class="pln">
</span><span class="pun">}</span></pre>

<h4 id="-4">
	خامسًا: الاقتباسات
</h4>

<p>
	لا يهم سواء كنت تفضل استخدام علامة اقتباس مفرد <code>'</code> أو مزدوج <code>"</code>، فلا يوجد فرق في كيفية تحليل جافا سكريبت لها. <strong>الواجب</strong> تطبيقه فقط هو الاتساق. <strong>لا تخلط علامات الاقتباس في نفس المشروع أبدًا. اختر نمطًا واحدًا والتزم به.</strong>
</p>

<h4 id="-5">
	سادسًا: نهاية الأسطر والأسطر الفارغة
</h4>

<p>
	يمكن للمسافة الفارغة أن تجعل مقارنة التغييرات diffs غير مقروءة في معالجة التحكم في الإصدارات، لذلك فكّر في إضافة أداة أو خطّاف قبل الإيداع pre-commit hook، ليزيل المسافات الفارغة في نهاية كل سطر، ويزيل الأسطر الفارغة تلقائيًا.
</p>

<h3 id="-6">
	التحقق من النوع
</h3>

<h4 id="-7">
	أولَا: الأنواع الفعلية
</h4>

<ul>
	<li>
		السلسلة النصية String:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_17" style=""><span class="kwd">typeof</span><span class="pln"> variable </span><span class="pun">===</span><span class="pln"> </span><span class="str">"string"</span></pre>

<ul>
	<li>
		الرقم Number:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_19" style=""><span class="kwd">typeof</span><span class="pln"> variable </span><span class="pun">===</span><span class="pln"> </span><span class="str">"number"</span></pre>

<ul>
	<li>
		القيمة البوليانية Boolean:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_21" style=""><span class="kwd">typeof</span><span class="pln"> variable </span><span class="pun">===</span><span class="pln"> </span><span class="str">"boolean"</span></pre>

<ul>
	<li>
		الكائن Object:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_23" style=""><span class="kwd">typeof</span><span class="pln"> variable </span><span class="pun">===</span><span class="pln"> </span><span class="str">"object"</span></pre>

<ul>
	<li>
		المصفوفة Array:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_25" style=""><span class="typ">Array</span><span class="pun">.</span><span class="pln">isArray</span><span class="pun">(</span><span class="pln"> </span><span class="pun">كائن</span><span class="pln">_</span><span class="pun">شبيه</span><span class="pln">_</span><span class="pun">بالمصفوفة</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
 </span><span class="pun">(إذا</span><span class="pln"> </span><span class="pun">أمكن</span><span class="pln"> </span><span class="pun">ذلك)</span></pre>

<ul>
	<li>
		العنصر Node:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_27" style=""><span class="pln">elem</span><span class="pun">.</span><span class="pln">nodeType </span><span class="pun">===</span><span class="pln"> </span><span class="lit">1</span></pre>

<ul>
	<li>
		القيمة الفارغة Null:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_29" style=""><span class="pln">variable </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span></pre>

<ul>
	<li>
		القيمة غير المعرفة undefined:
	</li>
</ul>

<pre class="ipsCode">variable === null
</pre>

<ul>
	<li>
		المتغيرات العامة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_31" style=""><span class="kwd">typeof</span><span class="pln"> variable </span><span class="pun">===</span><span class="pln"> </span><span class="str">"undefined"</span></pre>

<ul>
	<li>
		المتغيرات المحلية:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_33" style=""><span class="pln">variable </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">undefined</span></pre>

<ul>
	<li>
		الخاصيات Properities:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_35" style=""><span class="pln">object</span><span class="pun">.</span><span class="pln">prop </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pln">
object</span><span class="pun">.</span><span class="pln">hasOwnProperty</span><span class="pun">(</span><span class="pln"> prop </span><span class="pun">)</span><span class="pln">
</span><span class="str">"prop"</span><span class="pln"> in object</span></pre>

<h4 id="coercedtypes">
	ثانيًا: الأنواع القسرية أو الإجبارية Coerced Types
</h4>

<p>
	ضع بالحسبان ما يلي: ألقِ نظرةً على هذا الجزء من شيفرة <a href="https://academy.hsoub.com/programming/html/" rel="">HTML</a>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6288_37" style=""><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"foo-input"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"1"</span><span class="tag">&gt;</span></pre>

<p>
	وشيفرة جافا سكريبت التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_39" style=""><span class="com">// 3.B.1.1</span><span class="pln">
</span><span class="com">// ‏‎‫‫عُرّفت `foo` بقيمة `0` ونوعها `number`</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> foo </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

</span><span class="com">// typeof foo;</span><span class="pln">
</span><span class="com">// "number"</span><span class="pln">
</span><span class="pun">...</span><span class="pln">

</span><span class="com">// ‫في مكان ما في الكود، تحتاج إلى تحديث `foo` بقيمة جديدة مشتقة من عنصر إدخال</span><span class="pln">

foo </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"foo-input"</span><span class="pun">).</span><span class="pln">value</span><span class="pun">;</span><span class="pln">

</span><span class="com">// ‫إذا كنت تختبر `typeof foo` الآن، ستكون النتيجة `string`</span><span class="pln">
</span><span class="com">// ‫هذا يعني أنه إذا كان لديك منطق يختبر `foo` مثل</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">===</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  importantTask</span><span class="pun">();</span><span class="pln">

</span><span class="pun">}</span><span class="pln">

</span><span class="com">// ‫لن تُقيّم `()importantTask` أبدًا، على الرغم من أن `foo` لديه قيمة "1"</span><span class="pln">



</span><span class="com">// 3.B.1.2</span><span class="pln">
</span><span class="com">// ‫يمكنك حل هذه المشكلة من خلال استخدام التحويل الذكي باستخدام عوامل التشغيل ‫الأحادية: عوامل السالب `-` أو   الموجب `+`</span><span class="pln">

foo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"foo-input"</span><span class="pun">).</span><span class="pln">value</span><span class="pun">;</span><span class="pln">
</span><span class="com">// سيحوّل عامل الإيجاب الأحادي `^` العملية المُشير إليها على الجانب الأيمن إلى رقم</span><span class="pln">

</span><span class="com">// typeof foo;</span><span class="pln">
</span><span class="com">// "number"</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">===</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  importantTask</span><span class="pun">();</span><span class="pln">

</span><span class="pun">}</span><span class="pln">
</span><span class="com">// ‫ستُستدعى `()importantTask`</span></pre>

<p>
	فيما يلي بعض الحالات الشائعة مع عمليات التحويل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_41" style=""><span class="com">// 3.B.2.1</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  string </span><span class="pun">=</span><span class="pln"> </span><span class="str">"1"</span><span class="pun">,</span><span class="pln">
  bool </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">

number</span><span class="pun">;</span><span class="pln">
</span><span class="com">// 1</span><span class="pln">

number </span><span class="pun">+</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
</span><span class="com">// "1"</span><span class="pln">

string</span><span class="pun">;</span><span class="pln">
</span><span class="com">// "1"</span><span class="pln">

</span><span class="pun">+</span><span class="pln">string</span><span class="pun">;</span><span class="pln">
</span><span class="com">// 1</span><span class="pln">

</span><span class="pun">+</span><span class="pln">string</span><span class="pun">++;</span><span class="pln">
</span><span class="com">// 1</span><span class="pln">

string</span><span class="pun">;</span><span class="pln">
</span><span class="com">// 2</span><span class="pln">

bool</span><span class="pun">;</span><span class="pln">
</span><span class="com">// false</span><span class="pln">

</span><span class="pun">+</span><span class="pln">bool</span><span class="pun">;</span><span class="pln">
</span><span class="com">// 0</span><span class="pln">

bool </span><span class="pun">+</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
</span><span class="com">// "false"</span></pre>

<p>
	وهذه الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_43" style=""><span class="pln">    </span><span class="com">// 3.B.2.2</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  string </span><span class="pun">=</span><span class="pln"> </span><span class="str">"1"</span><span class="pun">,</span><span class="pln">
  bool </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

string </span><span class="pun">===</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="com">// false</span><span class="pln">

string </span><span class="pun">===</span><span class="pln"> number </span><span class="pun">+</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
</span><span class="com">// true</span><span class="pln">

</span><span class="pun">+</span><span class="pln">string </span><span class="pun">===</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="com">// true</span><span class="pln">

bool </span><span class="pun">===</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="com">// false</span><span class="pln">

</span><span class="pun">+</span><span class="pln">bool </span><span class="pun">===</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="com">// true</span><span class="pln">

bool </span><span class="pun">===</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="com">// false</span><span class="pln">

bool </span><span class="pun">===</span><span class="pln"> </span><span class="pun">!!</span><span class="pln">string</span><span class="pun">;</span><span class="pln">
</span><span class="com">// true</span></pre>

<p>
	وهذه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_45" style=""><span class="com">// 3.B.2.3</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> array </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="str">"a"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"b"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"c"</span><span class="pln"> </span><span class="pun">];</span><span class="pln">

</span><span class="pun">!!~</span><span class="pln">array</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"a"</span><span class="pun">);</span><span class="pln">
</span><span class="com">// true</span><span class="pln">

</span><span class="pun">!!~</span><span class="pln">array</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"b"</span><span class="pun">);</span><span class="pln">
</span><span class="com">// true</span><span class="pln">

</span><span class="pun">!!~</span><span class="pln">array</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"c"</span><span class="pun">);</span><span class="pln">
</span><span class="com">// true</span><span class="pln">

</span><span class="pun">!!~</span><span class="pln">array</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"d"</span><span class="pun">);</span><span class="pln">
</span><span class="com">// false</span><span class="pln">

</span><span class="com">// لاحظ أن ما ورد أعلاه كان ذكيًا بلا داع</span><span class="pln">

</span><span class="com">// ‫الرجاء استخدام الطريقة الواضحة لمقارنة القيمة التي تُرجع لـ IndexOf، مثل:</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="pln"> </span><span class="str">"a"</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	والشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_47" style=""><span class="com">// 3.B.2.4</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> num </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2.5</span><span class="pun">;</span><span class="pln">

parseInt</span><span class="pun">(</span><span class="pln"> num</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

</span><span class="com">// ‫بالضبط مثل...</span><span class="pln">

</span><span class="pun">~~</span><span class="pln">num</span><span class="pun">;</span><span class="pln">

num </span><span class="pun">&gt;&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

num </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

</span><span class="com">// الكل نتيجته 2</span><span class="pln">

</span><span class="com">// ‫مع ذلك، ضع في حسبانك أنه سيُتعامل مع الأرقام السالبة تعاملًا مختلفًا...</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> neg </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2.5</span><span class="pun">;</span><span class="pln">

parseInt</span><span class="pun">(</span><span class="pln"> neg</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

</span><span class="com">// الكل نتيجته 2</span><span class="pln">

</span><span class="pun">~~</span><span class="pln">neg</span><span class="pun">;</span><span class="pln">

neg </span><span class="pun">&gt;&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

</span><span class="com">// ‫الكل نتيجته -2</span><span class="pln">
</span><span class="com">// لكن...</span><span class="pln">

neg </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

</span><span class="com">// النتيجة هي 4294967294</span></pre>

<h3 id="-8">
	التقييم المشروط
</h3>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_49" style=""><span class="com">// 4.1.1</span><span class="pln">

</span><span class="com">// ‫عند تقييم ما إذا كان للمصفوفة طول (أي لها عناصر وليست فارغة)</span><span class="pln">

</span><span class="com">// بدلًا من هذا</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">

</span><span class="com">// ‫... قيّم صوابية القيمة، مثل هذه:</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">


</span><span class="com">// 4.1.2</span><span class="pln">
</span><span class="com">// ‫عند تقييم ما إذا كان المصفوفة فارغة فقط،</span><span class="pln">
</span><span class="com">// بدلًا من هذا</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">
</span><span class="com">// ‫... تقييم القيمة، مثل هذه:</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">!</span><span class="pln">array</span><span class="pun">.</span><span class="pln">length </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">


</span><span class="com">// 4.1.3</span><span class="pln">
</span><span class="com">// ‫عند تقييم ما إذا كان المصفوفة ذات قيمة وليست فارغة فقط</span><span class="pln">
</span><span class="com">// بدلًا من هذا</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> string </span><span class="pun">!==</span><span class="pln"> </span><span class="str">""</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">

</span><span class="com">// ‫... تقييم القيمة، مثل هذه:</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> string </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">


</span><span class="com">// 4.1.4</span><span class="pln">
</span><span class="com">// عند تقييم ما إذا كانت السلسلة النصية فارغة فقط</span><span class="pln">
</span><span class="com">// بدلًا من هذا</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> string </span><span class="pun">===</span><span class="pln"> </span><span class="str">""</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">
</span><span class="com">// ‫... قيّم خطأ القيمة، مثل هذه:</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">!</span><span class="pln">string </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">


</span><span class="com">// 4.1.5</span><span class="pln">
</span><span class="com">// عند تقييم ما إذا كان المرجع صوابًا</span><span class="pln">

</span><span class="com">// بدلًا من هذا</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">

</span><span class="com">// ‫... قيّم صواب القيمة أو خطأها كما تريد، واستفد من الإمكانيات المضمّنة</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">


</span><span class="com">// 4.1.6</span><span class="pln">
</span><span class="com">// ‫عند تقييم ما إذا كان قيمة المتغير خاطئة،</span><span class="pln">

</span><span class="com">// بدلًا من هذا</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">

</span><span class="com">// ‫...استخدم النفي لفرض التقييم الحقيقي</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">!</span><span class="pln">foo </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">

</span><span class="com">// ‫...كن حذرًا، سيتطابق هذا أيضًا مع هذه القيم: 0, ""، null,undefined , NaN</span><span class="pln">
</span><span class="com">// ‫إذا كان يجب عليك اختبار القيمة الخاطئة فاستخدم ما يلي:</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">


</span><span class="com">// 4.1.7</span><span class="pln">
</span><span class="com">// ‫عند تقييم ما إذا كان المرجع قيمته null أو undefined، ولكن ليس "" أو 0،</span><span class="pln">

</span><span class="com">// بدلًا من هذا</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> foo </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">


</span><span class="com">// ‫... الاستفادة من المعاملين "==" الذيَن يفرضان تحويلًا لنوع البيانات مثل هذا:</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">...</span><span class="pln">

</span><span class="com">// ‫تذكر أن استخدام المعاملين "==" سيطابق `null` مع كل من `null` و `undefined`</span><span class="pln">
</span><span class="com">// ‫ولكن لن يطابق `null` مع القيم `false` أو "" أو 0</span><span class="pln">

</span><span class="kwd">null</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">undefined</span></pre>

<p>
	قيّم <strong>دائمًا</strong> للحصول على أفضل النتائج، وأدقها، ما ورد أعلاه هو أسلوب توجيهي وليس مبدأ متزمت.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_51" style=""><span class="com">// 4.2.1</span><span class="pln">
</span><span class="com">// ‫ملاحظات فرض النوع Type coercion والتقييم</span><span class="pln">

</span><span class="com">// ‫تُفضّل `===` على `==` ما لم تتطلب الحالة تقييمًا فضفاضًا للنوع loose type evaluation</span><span class="pln">


</span><span class="com">// المعاملات "===" لا يفرض النوع، مما يعني أن:</span><span class="pln">


</span><span class="str">"1"</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="com">// خطأ</span><span class="pln">

</span><span class="com">// ‫أما المعاملَين `==` فهما يفرضان تحويل النوع مما يعني أن</span><span class="pln">

</span><span class="str">"1"</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="com">// صواب</span><span class="pln">


</span><span class="com">// 4.2.2</span><span class="pln">
</span><span class="com">/// القيم البوليانية وقيم الصواب والخطأ</span><span class="pln">

</span><span class="com">// القيم البوليانية</span><span class="pln">
</span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">

</span><span class="com">// القيم الصائبة</span><span class="pln">
</span><span class="str">"foo"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln">

</span><span class="com">// القيم الخاطئة</span><span class="pln">

</span><span class="str">""</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">NaN</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="lit">0</span></pre>

<h3 id="-9">
	الأسلوب العملي
</h3>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_53" style=""><span class="com">// 5.1.1</span><span class="pln">

</span><span class="com">// وحدة عملية</span><span class="pln">

</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> global </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> </span><span class="typ">Module</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">var</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> </span><span class="str">"secret"</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// هذه خاصية بوليانية </span><span class="pln">
      bool</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      </span><span class="com">// قيمة نصية ما</span><span class="pln">
      string</span><span class="pun">:</span><span class="pln"> </span><span class="str">"a string"</span><span class="pun">,</span><span class="pln">
      </span><span class="com">// خاصية المصفوفة</span><span class="pln">
      array</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">],</span><span class="pln">
      </span><span class="com">// خاصية الكائن</span><span class="pln">
      object</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        lang</span><span class="pun">:</span><span class="pln"> </span><span class="str">"en-Us"</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      getData</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// ‫احصل على القيمة الحالية لـ `data`.</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> data</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      setData</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> value </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// ‫عيّن قيمة `data` وأرجعها</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> value </span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">};</span><span class="pln">
      </span><span class="pun">})();</span><span class="pln">

      </span><span class="com">// قد تحدث أشياء أخرى هنا</span><span class="pln">


      </span><span class="com">// كشف وحدتنا للكائن العام</span><span class="pln">

      global</span><span class="pun">.</span><span class="typ">Module</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Module</span><span class="pun">;</span><span class="pln">

</span><span class="pun">})(</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	ألقِ نظرةً على الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_55" style=""><span class="com">// 5.2.1</span><span class="pln">
</span><span class="com">// باني عملي</span><span class="pln">

</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> global </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Ctor</span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">foo </span><span class="pun">=</span><span class="pln"> foo</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="typ">Ctor</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">getFoo </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">foo</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  </span><span class="typ">Ctor</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">setFoo </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> val </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">foo </span><span class="pun">=</span><span class="pln"> val </span><span class="pun">);</span><span class="pln">
   </span><span class="pun">};</span><span class="pln">


  </span><span class="com">// ‫لاستدعاء الباني دون الكلمة المفتاحية `new`، يمكنك فعل ذلك:</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> ctor </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Ctor</span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">


  </span><span class="com">// كشف الباني للكائن العام</span><span class="pln">
  global</span><span class="pun">.</span><span class="pln">ctor </span><span class="pun">=</span><span class="pln"> ctor</span><span class="pun">;</span><span class="pln">

</span><span class="pun">})(</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> </span><span class="pun">);</span></pre>

<h3 id="-10">
	التسمية
</h3>

<h4 id="compilercompressor">
	أولًا: أنت لست مصرّفًا compiler أو ضاغطًا compressor للشيفرة
</h4>

<p>
	ضع في بالك أنك لستَ <a href="https://academy.hsoub.com/programming/c/%D8%A7%D9%84%D9%81%D8%B5%D9%84-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%B5%D8%B1%D9%8A%D9%81-compilation-%D9%81%D9%8A-%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r976/" rel="">مصرّفًا compiler</a> أو ضاغطًا compressor بشريًا للشيفرة البرمجية، لذا لا تحاول أن تفعل ما يفترض أن يفعله المُصرّف أو الضاغط.
</p>

<p>
	الشيفرة البرمجية التالية هي مثال على التسمية السيئة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_57" style=""><span class="com">// 6.A.1.1</span><span class="pln">
</span><span class="com">// مثال على شيفرة برمجية ذي تسميات سيئة</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> q</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="pln">s</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> i</span><span class="pun">,</span><span class="pln">a</span><span class="pun">=[],</span><span class="pln">els</span><span class="pun">=</span><span class="pln">q</span><span class="pun">(</span><span class="str">"#foo"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">for</span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">els</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">a</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">els</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);}</span></pre>

<p>
	دون شك، لقد كتبتَ شيفرة برمجية سيئة مثل هذه، ونأمل ألا يحدث ذلك مجددًا.
</p>

<p>
	إليك نفس المنطق البرمجي، ولكن مع تسمية ألطف وأكثر عناية وجودة قراءة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_59" style=""><span class="com">// 6.A.2.1</span><span class="pln">
</span><span class="com">// مثال على شيفرة برمجية ذات تسميات أفضل</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> query</span><span class="pun">(</span><span class="pln"> selector </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="pln"> selector </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> idx </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  elements </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
  matches </span><span class="pun">=</span><span class="pln"> query</span><span class="pun">(</span><span class="str">"#foo"</span><span class="pun">),</span><span class="pln">
  length </span><span class="pun">=</span><span class="pln"> matches</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">;</span><span class="pln"> idx </span><span class="pun">&lt;</span><span class="pln"> length</span><span class="pun">;</span><span class="pln"> idx</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  elements</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln"> matches</span><span class="pun">[</span><span class="pln"> idx </span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إليك بعض المؤشرات الإضافية للتسمية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_61" style=""><span class="com">// 6.A.3.1</span><span class="pln">
</span><span class="com">// تسمية السلاسل النصية</span><span class="pln">

</span><span class="pun">`</span><span class="pln">dog</span><span class="pun">`</span><span class="pln"> is a string


</span><span class="com">// 6.A.3.2</span><span class="pln">
</span><span class="com">// تسمية المصفوفات</span><span class="pln">

</span><span class="pun">`</span><span class="pln">dogs</span><span class="pun">`</span><span class="pln"> is an array </span><span class="kwd">of</span><span class="pln"> </span><span class="pun">`</span><span class="pln">dog</span><span class="pun">`</span><span class="pln"> strings

</span><span class="com">// 6.A.3.3</span><span class="pln">
</span><span class="com">// تسمية الدوال، والكائنات، والنُسَخ</span><span class="pln">

camelCase</span><span class="pun">;</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> and </span><span class="kwd">var</span><span class="pln"> declarations

</span><span class="com">// 6.A.3.4</span><span class="pln">
</span><span class="com">// ‫تسمية الدوال البانية، ودوال النماذج الأولية prototypes، إلخ.</span><span class="pln">

</span><span class="typ">PascalCase</span><span class="pun">;</span><span class="pln"> </span><span class="kwd">constructor</span><span class="pln"> </span><span class="kwd">function</span><span class="pln">


</span><span class="com">// 6.A.3.5</span><span class="pln">

</span><span class="com">// تسمية التعابير النمطية</span><span class="pln">

rDesc </span><span class="pun">=</span><span class="pln"> </span><span class="com">//;</span><span class="pln">


</span><span class="com">// 6.A.3.6</span><span class="pln">
</span><span class="com">// ‫من دليل أسلوب مكتبة Google للـ Closure</span><span class="pln">
functionNamesLikeThis</span><span class="pun">;</span><span class="pln">
variableNamesLikeThis</span><span class="pun">;</span><span class="pln">
</span><span class="typ">ConstructorNamesLikeThis</span><span class="pun">;</span><span class="pln">
</span><span class="typ">EnumNamesLikeThis</span><span class="pun">;</span><span class="pln">
methodNamesLikeThis</span><span class="pun">;</span><span class="pln">
SYMBOLIC_CONSTANTS_LIKE_THIS</span><span class="pun">;</span></pre>

<h4 id="this">
	ثانيًا: أوجه الكلمة المفتاحية this
</h4>

<p>
	بعيدًا عن حالات الاستخدام المعروفة عمومًا للكلمات <code>call</code> و <code>apply</code>، يُفضّل دائمًا استخدام <code>(bind(this</code> أو ما يعادلها وظيفيًا لإنشاء تعريفات <code>BoundFunction</code> للاستدعاء لاحقًا. لا تلجأ إلى الاسم البديل aliasing إلا في حالة عدم توفر خيار أفضل.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_63" style=""><span class="com">// 6.B.1</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Device</span><span class="pun">(</span><span class="pln"> opts </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// فتح مجرى غير متزامن،</span><span class="pln">
  </span><span class="com">// سيُستدعى هذا استدعاء مستمرًا</span><span class="pln">

  stream</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln"> opts</span><span class="pun">.</span><span class="pln">path</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> data </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// حدّث القيمة الحالية لهذه النسخة</span><span class="pln">
    </span><span class="com">// بأحدث قيمة من</span><span class="pln">
    </span><span class="com">// مجرى المعلومات</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">;</span><span class="pln">

  </span><span class="pun">}.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

  </span><span class="com">//  التحكم في عدد مرات تشغيل الأحداث من</span><span class="pln">
  </span><span class="com">// نسخة الجهاز هذا</span><span class="pln">


  setInterval</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// انبعاث حدث مُقيّد</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">emit</span><span class="pun">(</span><span class="str">"event"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">),</span><span class="pln"> opts</span><span class="pun">.</span><span class="pln">freq </span><span class="pun">||</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">


</span><span class="com">// ‫تظاهر فقط بأننا ورثنا EventEmitter </span></pre>

<p>
	عندما لا ينجح ذلك، تتوفر وظيفة مكافئة لـ <code>bind.</code> في معظم مكتبات جافا سكريبت الحديثة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_65" style=""><span class="com">// 6.B.2</span><span class="pln">

</span><span class="com">// مثال: lodash/underscore, _.bind()</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Device</span><span class="pun">(</span><span class="pln"> opts </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

  stream</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln"> opts</span><span class="pun">.</span><span class="pln">path</span><span class="pun">,</span><span class="pln"> _</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> data </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">;</span><span class="pln">

  </span><span class="pun">},</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

  setInterval</span><span class="pun">(</span><span class="pln">_</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">emit</span><span class="pun">(</span><span class="str">"event"</span><span class="pun">);</span><span class="pln">

  </span><span class="pun">},</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">),</span><span class="pln"> opts</span><span class="pun">.</span><span class="pln">freq </span><span class="pun">||</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// مثال: jQuery.proxy</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Device</span><span class="pun">(</span><span class="pln"> opts </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

  stream</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln"> opts</span><span class="pun">.</span><span class="pln">path</span><span class="pun">,</span><span class="pln"> jQuery</span><span class="pun">.</span><span class="pln">proxy</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> data </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">;</span><span class="pln">

  </span><span class="pun">},</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

  setInterval</span><span class="pun">(</span><span class="pln"> jQuery</span><span class="pun">.</span><span class="pln">proxy</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">emit</span><span class="pun">(</span><span class="str">"event"</span><span class="pun">);</span><span class="pln">

  </span><span class="pun">},</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">),</span><span class="pln"> opts</span><span class="pun">.</span><span class="pln">freq </span><span class="pun">||</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// على سبيل المثال. dojo.hitch</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Device</span><span class="pun">(</span><span class="pln"> opts </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

  stream</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln"> opts</span><span class="pun">.</span><span class="pln">path</span><span class="pun">,</span><span class="pln"> dojo</span><span class="pun">.</span><span class="pln">hitch</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> data </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">;</span><span class="pln">

</span><span class="pun">})</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

  setInterval</span><span class="pun">(</span><span class="pln"> dojo</span><span class="pun">.</span><span class="pln">hitch</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">emit</span><span class="pun">(</span><span class="str">"event"</span><span class="pun">);</span><span class="pln">

  </span><span class="pun">}),</span><span class="pln"> opts</span><span class="pun">.</span><span class="pln">freq </span><span class="pun">||</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عرّف اسمًا بديلًا للكلمة <code>this</code> باستخدام <code>self</code> معرفًا، هذا يعرّضك للأخطاء بشدة ويجب تجنّبه كلما أمكن ذلك.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_67" style=""><span class="com">// 6.B.3</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Device</span><span class="pun">(</span><span class="pln"> opts </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> self </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

  stream</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln"> opts</span><span class="pun">.</span><span class="pln">path</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> data </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    self</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">

    setInterval</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

      self</span><span class="pun">.</span><span class="pln">emit</span><span class="pun">(</span><span class="str">"event"</span><span class="pun">);</span><span class="pln">

  </span><span class="pun">},</span><span class="pln"> opts</span><span class="pun">.</span><span class="pln">freq </span><span class="pun">||</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<h4 id="thisarg">
	ثالثًا: استخدم thisArg
</h4>

<p>
	تأتي العديد من توابع النماذج الأولية prototype methods لمكونات ES 5.1 المضمنة مع بصمة <code>thisArg</code> خاصة، والتي يجب استخدامها كلما أمكن ذلك.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_69" style=""><span class="com">// 6.C.1</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> obj</span><span class="pun">;</span><span class="pln">

obj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> f</span><span class="pun">:</span><span class="pln"> </span><span class="str">"foo"</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">:</span><span class="pln"> </span><span class="str">"bar"</span><span class="pun">,</span><span class="pln"> q</span><span class="pun">:</span><span class="pln"> </span><span class="str">"qux"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">(</span><span class="pln"> obj </span><span class="pun">).</span><span class="pln">forEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln"> key </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">


  </span><span class="com">// ‫تشير |this| إلى `obj`</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">[</span><span class="pln"> key </span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

</span><span class="pun">},</span><span class="pln"> obj </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ← ‫آخر arg هو `thisArg`</span><span class="pln">

</span><span class="com">// النتيجة</span><span class="pln">

</span><span class="com">// "foo"</span><span class="pln">
</span><span class="com">// "bar"</span><span class="pln">
</span><span class="com">// "qux"</span></pre>

<p>
	يمكن أن تُستخدم <code>thisArg</code> مع <code>Array.prototype.every</code>، و <code>Array.prototype.forEach</code>، و <code>Array.prototype.some</code>، و <code>Array.prototype.map</code>، و <code>Array.prototype.filter</code>.
</p>

<h3 id="-11">
	متفرقات
</h3>

<p>
	سيعمل هذا القسم على توضيح الأفكار والمفاهيم التي لا ينبغي التعصّب لها، وبدلًا من ذلك، فإننا نشجع الفضول حول الاتفاقيات الحالية ومحاولة إيجاد طرق أفضل لكتابة جافا سكريبت.
</p>

<p>
	أولًا: يجب تجنّب استخدام <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A9-switch-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r780/" rel=""><code>switch</code></a>، إذ سيدرج التتبع بالتوابع الحديثة الدوال التي تحتوي على عبارات switch في القائمة السوداء.
</p>

<p>
	يبدو أن هناك تحسينات جذرية في تنفيذ عبارات <code>switch</code> في أحدث إصدارات Firefox و Chrome.
</p>

<p>
	يمكن ملاحظة التحسينات الملحوظة على <a href="https://github.com/rwaldron/idiomatic.js/issues/13" rel="external nofollow">الرابط</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_71" style=""><span class="com">// 7.A.1.1</span><span class="pln">
</span><span class="com">// ‫مثال على عبارة switch</span><span class="pln">

</span><span class="kwd">switch</span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"alpha"</span><span class="pun">:</span><span class="pln">
    alpha</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"beta"</span><span class="pun">:</span><span class="pln">
    beta</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// القيمة الافتراضي</span><span class="pln">
    </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// 7.A.1.2</span><span class="pln">

</span><span class="com">// ‫البديل القابل للتركيب وإعادة الاستخدام هو استخدام الكائنات لتخزين "الحالات"</span><span class="pln">
</span><span class="com">// ‫واستخدم دالة للتفويض:</span><span class="pln">



</span><span class="kwd">var</span><span class="pln"> cases</span><span class="pun">,</span><span class="pln"> delegator</span><span class="pun">;</span><span class="pln">

</span><span class="com">// المثال يرجع بعض النتائج للتوضيح فقط</span><span class="pln">
cases </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alpha</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">
    </span><span class="com">// رجوع</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="str">"Alpha"</span><span class="pun">,</span><span class="pln"> arguments</span><span class="pun">.</span><span class="pln">length </span><span class="pun">];</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  beta</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">

    </span><span class="com">// رجوع</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="str">"Beta"</span><span class="pun">,</span><span class="pln"> arguments</span><span class="pun">.</span><span class="pln">length </span><span class="pun">];</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  _default</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// تعليمات برمجية</span><span class="pln">

    </span><span class="com">// رجوع</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="str">"Default"</span><span class="pun">,</span><span class="pln"> arguments</span><span class="pun">.</span><span class="pln">length </span><span class="pun">];</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

delegator </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> args</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> delegate</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// ‫تحويل قائمة الوسطاء إلى مصفوفة</span><span class="pln">
  args </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[].</span><span class="pln">slice</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="pln"> arguments </span><span class="pun">);</span><span class="pln">

  </span><span class="com">// إزاحة مفتاح الحالة من الوسطاء </span><span class="pln">
  key </span><span class="pun">=</span><span class="pln"> args</span><span class="pun">.</span><span class="pln">shift</span><span class="pun">();</span><span class="pln">

  </span><span class="com">// تعيين معالج الحالة الافتراضي</span><span class="pln">
  delegate </span><span class="pun">=</span><span class="pln"> cases</span><span class="pun">.</span><span class="pln">_default</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// اشتقاق الدالة لتفويض العملية</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> cases</span><span class="pun">.</span><span class="pln">hasOwnProperty</span><span class="pun">(</span><span class="pln"> key </span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    delegate </span><span class="pun">=</span><span class="pln"> cases</span><span class="pun">[</span><span class="pln"> key </span><span class="pun">];</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">


  </span><span class="com">// يمكن ضبط وسيط النطاق على شيء محدد،</span><span class="pln">
  </span><span class="com">// ‫في هذه الحالة، |null| ستكفي</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> delegate</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> args </span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// 7.A.1.3</span><span class="pln">
</span><span class="com">// ضع الواجهة البرمجية في 7.A.1.2 لتعمل:</span><span class="pln">

delegator</span><span class="pun">(</span><span class="pln"> </span><span class="str">"alpha"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="com">// [ "Alpha", 5 ]</span><span class="pln">


</span><span class="com">// ‫يمكن بسهولة طبعًا تعيين قيمة مفتاح "الحالة" `case` بناءً على بعض المواقف المختلفة الأخرى.</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> caseKey</span><span class="pun">,</span><span class="pln"> someUserInput</span><span class="pun">;</span><span class="pln">

</span><span class="com">// ربما نوع من المدخلات؟</span><span class="pln">
someUserInput </span><span class="pun">=</span><span class="pln"> </span><span class="lit">9</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> someUserInput </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  caseKey </span><span class="pun">=</span><span class="pln"> </span><span class="str">"alpha"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  caseKey </span><span class="pun">=</span><span class="pln"> </span><span class="str">"beta"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// أو</span><span class="pln">

caseKey </span><span class="pun">=</span><span class="pln"> someUserInput </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">"alpha"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"beta"</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// ثم</span><span class="pln">
delegator</span><span class="pun">(</span><span class="pln"> caseKey</span><span class="pun">,</span><span class="pln"> someUserInput </span><span class="pun">);</span><span class="pln">
</span><span class="com">// [ "Beta", 1 ]</span><span class="pln">

</span><span class="com">// وطبعًا</span><span class="pln">
delegator</span><span class="pun">();</span><span class="pln">
</span><span class="com">// [ "Default", 0 ]</span></pre>

<p>
	ثانيًا: يمكن أن يؤدي إرجاع القيم مقدمًا إلى تحسين إمكانية القراءة وليس له تأثير يذكر على الأداء.
</p>

<p>
	ألقِ نظرةً على الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6288_73" style=""><span class="com">// 7.B.1.1</span><span class="pln">
</span><span class="com">// سيء:</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> returnLate</span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> ret</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    ret </span><span class="pun">=</span><span class="pln"> </span><span class="str">"foo"</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    ret </span><span class="pun">=</span><span class="pln"> </span><span class="str">"quux"</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> ret</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// جيد</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> returnEarly</span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> foo </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"foo"</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"quux"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3 id="nativeandhostobjects">
	الكائنات الأصلية والمضيفة Native and Host Objects
</h3>

<p>
	المبدأ الأساسي هو: "لا تفعل أشياء غبية وسيكون كل شيء على ما يرام".
</p>

<h3 id="-12">
	التعليقات
</h3>

<ul>
	<li>
		تُفضّل التعليقات المكونة من سطر واحد أعلى الشيفرة.
	</li>
	<li>
		تعدد التعليقات شيء جيد كذلك.
	</li>
	<li>
		تجنب التعليقات في نهاية السطر.
	</li>
	<li>
		يعد أسلوب JSDoc جيد، ولكن يستغرق وقتًا أطول.
	</li>
</ul>

<h3 id="-13">
	شيفرة لغة واحدة
</h3>

<p>
	يجب أن تكون البرامج مكتوبة بلغة واحدة، مهما كانت <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغة البرمجة</a> تلك، حسب ما يمليه المشرف أو الفريق.
</p>

<p>
	ترجمة -وبتصرف- لدليل <a href="https://github.com/rwaldron/idiomatic.js" rel="external nofollow">Principles of Writing Consistent, Idiomatic JavaScript</a> لصاحبه Rick Waldron وكل المساهمين.
</p>

<h2 id="-14">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AF%D9%84%D9%8A%D9%84-airbnb-%D9%84%D9%86%D9%85%D8%B7-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r632/" rel="">دليل Airbnb لنمط جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%B5%D9%81%D8%B1-%D8%AD%D8%AA%D9%89-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81-r2046/" rel="">تعلم لغة جافا سكريبت من الصفر حتى الاحتراف</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1233/" rel="">الدوال في جافاسكريبت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2178</guid><pubDate>Tue, 14 Nov 2023 13:00:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x644;&#x645; &#x644;&#x63A;&#x629; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A; &#x645;&#x646; &#x627;&#x644;&#x635;&#x641;&#x631; &#x62D;&#x62A;&#x649; &#x627;&#x644;&#x627;&#x62D;&#x62A;&#x631;&#x627;&#x641;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%B5%D9%81%D8%B1-%D8%AD%D8%AA%D9%89-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81-r2046/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_08/-----.png.5f87c359dfc74c977bad6eb5cde5b54b.png" /></p>
<p>
	نشرح لك في مقال اليوم طريقة تعلم جافا سكريبت التي تُعَد واحدةً من أكثر لغات البرمجة شهرة وشعبية في أوساط المطورين حول العالم والتي تستخدم من قبل معظم إن لم يكن جميع التطبيقات والمواقع التي تتصفحها يوميًا.
</p>

<p>
	سوف نستعرض في البداية مفهوم لغة جافا سكريبت ونوضح أبرز تطبيقاتها واستخداماتها، كما سنتعرف على أهم أطر عمل جافا سكريبت ومكتباتها، ومن ثمة نكتشف الفرق بين لغة جافا سكريبت ولغة البرمجة جافا ولغة Typescript، وختامًا سنوفر لك أهم الخطوات والمصادر المفيدة التي تساعدك على تعلم جافا سكريبت من الصفر حتى الاحتراف.
</p>

<h2>
	ما هي لغة جافا سكريبت JavaScript
</h2>

<p style="text-align: center;">
	<img alt="ما هي جافا سكريبت JavaScript.png" class="ipsImage ipsImage_thumbnailed" data-fileid="132569" data-unique="nurflmbeh" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_08/JavaScript.thumb.png.5556ae0eba05fec5aea215aae4baa694.png">
</p>

<p>
	لعلك تتساءل ما هي جافا سكريبت JavaScript أو ما يعرف اختصارًا JS؟ الجواب ببساطة هو أنها لغة برمجة عالية المستوى تجعل مواقع الويب تفاعلية، فمن خلال جافا سكريبت صار بإمكان مطوري المواقع إضافة وظائف تفاعلية لمواقع الويب وتمكين المستخدمين من التفاعل مع عناصر الموقع مثل القوائم المنسدلة ونماذج الاتصال؛ كما مكنت لغة جافا سكريبت المطورين من إدخال التأثيرات الحركية على المواقع، مثل الرسوم المتحركة ومشغلات الفيديو والخرائط التفاعلية.
</p>

<p>
	تُعَد جافا سكريبت إحدى لغات البرمجة الثلاثة الرئيسية المستخدمة في <strong>تطوير الواجهات الأمامية لمواقع الويب</strong> فهي تستخدم إلى جانب لغة <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> المسؤولة عن تحديد بنية موقع الويب، ولغة <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> التي تنسق عناصر موقع الويب، في حين يتجلى دور لغة جافا سكريبت <a href="https://wiki.hsoub.com/JavaScript" rel="external">JavaScript</a> في إضافة وظائف لموقع الويب وتمكين التفاعل مع محتوى الموقع من خلال ما يسمى بنموذج تمثيل المستند ككائن Document Object Model أو النموذج الشجري، والذي يعرف اختصارًا <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">DOM</a>.
</p>

<p>
	ومفهوم DOM ببساطة ما هو سوى عملية تمثيل صفحات موقع الويب بطريقة خاصة بحيث يُعَد كل عنصر من عناصر الصفحة عبارة عن كائن Object يمكن الوصول له وتعديله والتحكم به بواسطة جافا سكريبت، وللمزيد من المعلومات حول المفهوم DOM وتعلم كيفية التعامل معه من خلال لغة جافا سكريبت يمكنك الاطلاع على مقال <a href="https://academy.hsoub.com/programming/html/%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%B4%D8%AC%D8%B1%D8%A9-dom-%D8%A7%D9%84%D8%AE%D9%81%D9%8A%D8%A9-r1353/" rel="">مكونات الويب: التعامل مع شجرة DOM الخفية</a>.
</p>

<p>
	كذلك، تُعَد جافا سكريبت اليوم <strong>لغة برمجة متعددة الأغراض</strong>، فلا يقتصر استخدامها على تطوير الواجهات الأمامية للويب فقط، فبعد ظهور بيئة <a href="https://wiki.hsoub.com/Node.js/Topics" rel="external">Node.js</a> وظهور أطر العمل والمكتبات المختلفة -التي سنتعرف عليها تباعًا في هذا المقال- أصبحت لغة جافا سكريبت قادرةً على العمل على الواجهة الخلفية لمواقع الويب، بمعنى العمل من <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-r783/" rel="">طرف الخادم</a> والتفاعل مع <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">قواعد البيانات</a>، كما صارت تستخدم في العديد من <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AC%D8%A7%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">مجالات البرمجة</a>.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			استفد من تقنيات جافا سكريبت في بناء موقع آمن وفعّال
		</p>

		<p class="banner-subtitle">
			وظّف مبرمج جافا سكريبت خبير على مستقل
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://mostaql.com/freelancers/skill/javascript" rel="external">أضف مشروعك الآن</a>
		</div>
	</div>
</div>

<h2>
	مثال على استخدام لغة جافا سكريبت في المتصفح
</h2>

<p>
	تحتوي معظم المتصفحات الرئيسية على قارئ جافا سكريبت مضمّن يقرأ التعليمات البرمجية ويفسرها، مثل تعليمة تغيير نص عنصر معروض على الصفحة أو الحصول على قيمة ما من المستخدم ومعالجتها وعرض النتيجة في المتصفح؛ حيث كل ما تحتاجه لكتابة كود جافا سكريبت الخاص بك هو محرر نصوص بسيط مثل المفكرة أو <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AD%D8%B1%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r666/" rel="">محررات شيفرات برمجية</a> مثل فيجوال ستوديو VS Code أو Atom أو Sublime أو بيئة تطوير متكاملة IDEs لجافا سكريبت مثل IntelliJ IDEA و Komodo IDE، أو بيئة تطوير سحابية مثل CopePen، لكي تساعدك في كتابة التعليمات البرمجية وتسهل عليك اكتشاف الأخطاء.
</p>

<p>
	عندما يقرأ المتصفح ملف HTML الخاص بك سيبدأ بقراءة هذا الملف سطرًا سطرًا من أعلى إلى أسفل ويفسره ويعرضه على الشاشة. وعندما يصل إلى شيفرات جافا سكريبت، فإنه يشغّل هذه الشيفرات بالكامل قبل المتابعة إلى أسفل الصفحة.
</p>

<p>
	يمكن تضمين أكواد جافا سكريبت ضمن كود HTML بطريقتين إما من خلال تضمين شيفراتها البرمجية بين الوسمين <code>&lt;script&gt;</code> و <code>&lt;script/&gt;</code> أو من خلال كتابة الأكواد في ملف بالامتداد js، وتضمين هذا الملف ضمن كود HTML بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1510_10" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pln"> src</span><span class="pun">=</span><span class="str">"path-to-javascript-file.js"</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	على سبيل المثال، كود جافا سكريبت التالي يستخدم لتغيير لون خلفية صفحة الويب عند مرور مؤشر الفأرة فوق اللون المطلوب
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1510_15" style=""><span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">dir</span><span class="pun">=</span><span class="atv">"rtl"</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"ar"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;head&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> bgChange</span><span class="pun">(</span><span class="pln">bg</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> bg</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">

</span><span class="tag">&lt;h2&gt;</span><span class="pln">مثال على تغيير لون خلفية الصفحة</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
</span><span class="tag">&lt;p&gt;</span><span class="pln">اختر اللون الذي تفضله</span><span class="tag">&lt;/p&gt;</span><span class="pln">

</span><span class="tag">&lt;table</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">width</span><span class="pun">:</span><span class="lit">300px</span><span class="pun">;</span><span class="kwd">height</span><span class="pun">:</span><span class="lit">100px</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;td</span><span class="pln"> </span><span class="atn">onmouseover</span><span class="pun">=</span><span class="atv">"</span><span class="pln">bgChange</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">backgroundColor</span><span class="pun">)</span><span class="atv">"</span><span class="pln"> 
    </span><span class="atn">onmouseout</span><span class="pun">=</span><span class="atv">"</span><span class="pln">bgChange</span><span class="pun">(</span><span class="str">'transparent'</span><span class="pun">)</span><span class="atv">"</span><span class="pln">
    </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">background-color</span><span class="pun">:</span><span class="lit">#89CFF0</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/td&gt;</span><span class="pln">
    </span><span class="tag">&lt;td</span><span class="pln"> </span><span class="atn">onmouseover</span><span class="pun">=</span><span class="atv">"</span><span class="pln">bgChange</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">backgroundColor</span><span class="pun">)</span><span class="atv">"</span><span class="pln"> 
    </span><span class="atn">onmouseout</span><span class="pun">=</span><span class="atv">"</span><span class="pln">bgChange</span><span class="pun">(</span><span class="str">'transparent'</span><span class="pun">)</span><span class="atv">"</span><span class="pln">
    </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">background-color</span><span class="pun">:</span><span class="lit">#FFBF00</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
</span><span class="tag">&lt;/table&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	عند استعراض الصفحة السابقة في المتصفح سنحصل على النتيجة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="gif" data-fileid="132575" href="https://academy.hsoub.com/uploads/monthly_2023_08/javascript.gif.d22a303a9d77f24b45f688feb39c3fbf.gif" rel=""><img alt="مثال على javascript.gif" class="ipsImage ipsImage_thumbnailed" data-fileid="132575" data-ratio="51.83" data-unique="ekdqugozi" style="width: 600px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_08/javascript.thumb.gif.b75318e6a92b243cfa8e676a65e4c3a8.gif"></a>
</p>

<h2>
	كيف أصبحت لغة جافا سكريبت تعمل من طرف السيرفر؟
</h2>

<p>
	بدأت جافا سكريبت حياتها كما ذكرنا سابقًا كلغة برمجة تعمل ضمن المتصفح، لكن كانت هناك عدة محاولات لجعلها تعمل خارج المتصفح، فقد حاولت شركة نيتسكيب من البداية تطوير بيئة عمل تسمى LiveWire يمكنها أن تعرض صفحات الويب الديناميكية باستخدام جافا سكريبت التي تنفذ على الخوادم، غير أن هذه التجربة باءت بالفشل سريعًا.
</p>

<p>
	بعد فترة وجيزة وتحديدًا في عام 2009 كتب مهندس البرمجيات في شركة جوجل ريان داهل Ryan Dahl بيئة تشغيل مفتوحة المصدر ومتعددة المنصات لجافا سكريبت، وسماها <a href="https://wiki.hsoub.com/Node.js" rel="external">Node.JS</a>، التي وفرت طريقةً لتنفيذ التعليمات البرمجية لجافا سكريبت من طرف الخادم، كما أرفقت هذه البيئة بنظام إدارة الحزم يسمى Node Package Manager أو اختصارًا <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D9%85%D8%AF%D9%8A%D8%B1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-npm-%D9%81%D9%8A-nodejs-r1465/" rel="">npm </a>الذي ساعد كثيرًا على تنظيم وإدارة حزم البرمجيات التي يتم التعامل معها في المشاريع البرمجية. ولمزيد من المعلومات حول التعامل مع مدير الحزم npm في مشاريع Node.JS وأهم مميزاته وطريقة تشغيل المهام باستخدامه، أنصح بمطالعة الفيديو التالي <a href="https://youtu.be/NseEi4a8_rY" rel="external nofollow">استخدام مدير الحزم npm</a>
</p>

<h2>
	ما هي Node.JS وما أهميتها؟
</h2>

<p>
	Node.JS هي بيئة تشغيل للغة جافا سكريبت مسؤولة عن تشغيل ملفات جافا سكريبت خارج المستعرض، وبالتالي أصبح لدى المطورين طريقتان لتشغيل كود جافا سكريبت، الأولى أن تكون أكواد جافا سكريبت ضمن موقع ويب وتنفذ ضمن متصفح الويب، والثانية تشغيل أكواد جافا سكريبت باستقلالية عن المتصفح باستخدام Node.JS.
</p>

<p>
	عند تشغيل كود جافا سكريبت في المتصفح، سيكون بإمكانك الوصول إلى عناصر HTML وتعديلها والتحكم بها؛ أما عند تشغيلها في Node.JS، فلن يكون هناك ملف HTML يمكن لجافا سكريبت الوصول إليه، بل سيعمل الكود باستقلالية، لكنك ستتمكن في هذه الحالة الوصول إلى نظام الملفات على جهازك والتعامل معها.
</p>

<p>
	كانت Node.JS في البداية مدعومةً على أنظمة تشغيل لينكس وماك أو إس فقط، ثم دعمت لاحقًا من قبل معظم أنظمة التشغيل الأخرى. وعلى الرغم من أن Node.JS لم تكن المحاولة الأولى لجعل جافا سكريبت تعمل على الخادم، إلا أنها كانت أول محاولة تنجح فعليًا، حيث شكلت نقطةً هامةً في مسيرة تطور جافا سكريبت ووصولها لهذه الشهرة والشعبية.
</p>

<p>
	وللعلم، لم تكن Node.JS هي التقنية الوحيدة من طرف الخادم التي تستخدم JavaScript، فقد طورت مايكروسوفت لغتها الخاصة <strong>JScript</strong> التي دُعمت لأول مرة في متصفح إنترنت إكسبلورر3 عام 1996، لكنها عانت من مشاكل أمنية عديدة وظهرت فيها مجموعة من الأخطاء التي دفعت مايكروسوفت لتعطيلها.
</p>

<p>
	كما طورت مايكروسوفت لغة <strong>VBScript</strong> وهي مجموعة فرعية من لغة البرمجة فيجوال بيزيك Visual Basic المعدة للعمل على مستعرض الويب إنترنت إكسبلورر وحاولت هذه اللغة منافسة لغة جافا سكريبت، لكنها لم تنجح بذلك، فقد كان مستعرض إنترنت إكسبلورر المتصفح الوحيد الذي دعم هذه اللغة. وكما تعرف، فقد أوقف هذا المتصفح اعتبارًا من حزيران/ يونيو 2022، لذا وفرت مايكروسوفت ميزة VBScript في متصفح Microsoft Edge فقط من أجل المستخدمين الذين يحتاجون إلى تشغيل تطبيق ويب قديم يحتوي على شيفرات VBScript.
</p>

<p>
	على هذا الأساس، تمكنك Node.js من إثبات وجودها واعتمادها كتقنية ناجحة لتحرير جافا سكريبت من قيود المتصفح وجعلها تتحول إلى لغة شاملة تعمل في الواجهة الخلفية Back-end وفي الواجهة الأمامية Front-end وتستخدم في تطوير جميع أنواع التطبيقات سواء تطبيقات السيرفر أو الجوال تطبيقات سطح المكتب وهذا شجع المطورين والمبرمجين على التوجه نحو تعلم جافا سكريبت واحترافها.
</p>

<h2>
	أهمية تعلم لغة جافا سكريبت
</h2>

<p>
	اختيرت لغة البرمجة جافا سكريبت على أنها اللغة الأكثر استخدامًا بين المطورين المحترفين والمبتدئين على حد سواء، فهي تستخدم من قبل أكثر من 63% من المطورين واحتفظت بمركز الصدارة للعام العاشر على التوالي بحسب ما أظهر <a href="https://survey.stackoverflow.co/2022/#technology-most-popular-technologies" rel="external nofollow">استطلاع الرأي الذي أجراه موقع التطوير الشهير StackOverflow لعام 2022</a>
</p>

<p style="text-align: center;">
	<img alt="جافا سكريبت التقنية الأكثر شيوعًا.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="132567" data-unique="4rol6vmcu" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_08/.thumb.PNG.806f220f74845c281e4f3fbac609fdf6.PNG">
</p>

<p>
	ستجد أن النسبة الأكبر من المستودعات البرمجية مفتوحة المصدر المستضافة على موقع GitHub مكتوبة بلغة جافا سكريبت، وهذا إن دل على شيء، فإنما يدل على مدى أهمية هذه اللغة ومدى شهرتها بين المبرمجين.
</p>

<p>
	تبرز أهمية جافا سكريبت كذلك بأنها لغة سهلة الاستخدام والتعلم، فهي لغة عالية المستوى وقريبة للغة الطبيعة، كما أنها تكون مثبتة ضمنيًا في معظم المتصفحات، ولست بحاجة للقيام بأي إجراء لإعداد بيئة التطوير الخاصة بها ويمكنك كتابة تعليماتها وتشغيلها ورؤية نتائجها على عناصر صفحات الويب مباشرةً دون الحاجة لأي إعداد لبيئة التطوير الخاصة بك، ما يجعلها واحدةً من <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D9%87%D9%84-%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">أسهل لغات البرمجة للمبتدئين</a>
</p>

<p>
	تعد جافا سكريبت أيضًا لغةً ممتازةً ومثاليةً للمبرمجين الذين يرغبون في التعرف على <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">أساسيات البرمجة</a>، فهي سهلة التعلم وتفيدهم طوال حياتهم المهنية، فبمجرد تعلم مبادئها الأساسية ستتمكن من تطبيقها بسهولة على أي لغة برمجة أخرى تريد تعلمها سواء <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a> أو <a href="https://academy.hsoub.com/programming/java/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%85%D8%A7-%D9%87%D9%8A%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-java-r1515/" rel="">جافا</a> أو <a href="https://academy.hsoub.com/programming/cpp/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-c-r802/" rel="">C++</a>‎ أو غيرها من لغات البرمجة.
</p>

<p>
	إضافةً إلى سهولة التعلم، تُعَد جافا سكريبت أداةً قوية، فلكونها لغة متعددة المجالات والاستخدامات ويمكنك استثمارها في الكثير من المجالات مثل تطوير مواقع وتطبيقات الويب وتطبيقات الجوال وبناء تطبيقات سطح المكتب، فهي تستخدم أيضًا في مجال إنترنت الأشياء (<a href="https://academy.hsoub.com/programming/os-embedded-systems/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-%D8%A7%D9%84%D8%A3%D8%B4%D9%8A%D8%A7%D8%A1-iot-r1514/" rel="">IoT</a>) والعديد من المجالات الأخرى التي سنتحدث عنها بمزيد من التفصيل في فقرة لاحقة؛ ولهذا تستخدمها المواقع والتطبيقات التابعة لأهم الشركات التقنية مثل جوجل ويويتوب وويكيبيديا وأمازون وفيسبوك ولينكدإن وتوتير.
</p>

<p>
	من ناحية أخرى، لغة جافا سكريبت لا تتوقف عن النمو والتطور، وهو ما ينبئ بأن المستقبل سيظل واعدًا لهذه اللغة، إذ تتمتع جافا سكريبت بمجتمع نشط وفعال يعمل بصورة مستمرة على تطوير إصدارات جديدة لأدوات وأطر عمل ومكتبات جديدة تعتمد على جافا سكريبت وتتيح للمطورين إنشاء برامجهم وتطبيقاتهم بسهولة وبساطة دون الغوص في تفاصيل اللغة ويقدم لك الدعم والمساعدة في حل أي مشكلة تواجهك في التعامل معها.
</p>

<h2>
	لغة جافا سكريبت في سوق العمل
</h2>

<p>
	تُعَد جافا سكريبت واحدةً من أكثر المهارات طلبًا والأعلى أجرًا في سوق العمل التقني، إذ هناك طلب كبير على مطوري جافا سكريبت ولا غرابة في ذلك، فجافا سكريبت تستخدم تقريبًا في حوالي 98٪ من مواقع الويب، وبالتالي تحتاج هذه المواقع إلى مطورين لإدارتها وصيانتها.
</p>

<p>
	ومن ناحية الأجور، يتقاضى مطورو جافا سكريبت أجورًا عالية، وبالرغم من أن الأجور تتفاوت بناءً على عدة عوامل أهمها الموقع الجغرافي وسنوات الخبرة التي يملكها المطور، لكن تبقى أجور مطوري جافا سكريبت مرتفعةً مقارنةً بباقي المهن وبالمقارنة مع عدة لغات برمجية أخرى.
</p>

<p>
	أظهر <a href="https://survey.stackoverflow.co/2022/#top-paying-technologies" rel="external nofollow">استطلاع الرأي الذي أجراه موقع ستاك أوفرفلو</a> حول التقنيات الأعلى أجرًا أن مطوري جافا سكريبت يتقاضون رواتب سنوية تقدر وسطيًا بحوالي 65000 دولارًا وهو مبلغ كبير مقارنةً بعدة لغات وتقنيات برمجية شائعة الاستخدام. وتسعى الشركات والمؤسسات لتوظيف مطوري جافا سكريبت أكفاء وتدفع لهم رواتب مجزية.
</p>

<p style="text-align: center;">
	<img alt="رواتب مطوري جافا سكريبت.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="132568" data-unique="zgfcj007a" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_08/.thumb.PNG.14a6e13a97e3d238a2c14ff3746841ca.PNG">
</p>

<p>
	بالتالي إذا كنت حريصًا على ضمان مستقبل وظيفي مستقر وتسعى للحصول على وظيفة مرموقة وذات أجر مرتفع، فإن جافا سكريبت تُعَد أداةً قويةً ومتعددة الاستخدامات، يعني من خلال تعلمها يمكن أن تحقق لك ما تطمح له بسهولة.
</p>

<h2>
	ما هي أهم مكتبات وأطر لغة جافا سكريبت؟
</h2>

<p>
	توفر لغة جافا سكريبت العديد من المكتبات وأطر العمل التي تتضمن مجموعةً من التعليمات البرمجية المكتوبة مسبقًا والجاهزة للاستخدام والمختبرة، والتي تسرع من وتيرة عمل المبرمجين في تطوير المشاريع وتجعله أبسط وأسرع وأكثر كفاءة.
</p>

<p>
	<a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-framework/" rel="">إطار العمل framework في البرمجة</a> هو في الأساس مكتبة من التعليمات البرمجية للغة معينة، وهو بمثابة مخطط عام لبناء مشروعك البرمجي، فهو يمنحك هيكلًا للعمل من خلاله ويحتوي على مجموعة من المكونات والأدوات الجاهزة للاستخدام بدلًا من كتابتها من الصفر؛ كما أنه يوفر نهجًا منظمًا لكتابة تعليمات برمجية منظمة ومختصرة ومقروءة.من أشهر أطر عمل جافا سكريبت نذكر أنغولار <a href="https://academy.hsoub.com/programming/javascript/angular/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-angular-%D9%88%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-firestore-r1409/" rel="">Angular</a> وأمبر Ember وفيو <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1664/" rel="">Vue</a>.
</p>

<p>
	أما المكتبة library، فهي تتضمن كذلك مجموعةً من التعليمات البرمجية الجاهزة للاستخدام، لكنها تكون محدودةً أكثر من أطر العمل وتستخدم عادةً من أجل حالات مخصصة وتنفذ وظائف وميزات معينة، على سبيل المثال تُعَد كل من <a href="https://wiki.hsoub.com/jQuery" rel="external">جي كويري jQuery</a> ورياكت <a href="https://academy.hsoub.com/programming/javascript/react/%D8%A8%D8%AF%D8%A1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D9%85%D9%83%D8%AA%D8%A8%D8%A9-react-r1569/" rel="">React</a> و Lodash أمثلةً على مكتبات جافا سكريبت التي توفر عليك كتابة عشرات الأسطر البرمجية لتحقيق وظائف محددة في تطبيقك.
</p>

<p>
	ولكي تدرك أهمية استخدام المكتبات والأطر، تخيل أنك على سبيل المثال تبني منزلًا خاصًا بك، بحيث يمكنك إما بناؤه من الصفر وهذا سيستغرق وقتًا وجهدًا، أو بناؤه باستخدام عناصر جاهزة مسبقة الصنع تستوردها لموقع منزلك وتجمّعها بكل سهولة. بنفس الطريقة توفر لك أطر ومكتبات جافا سكريبت كل شيء وتحسن لك الأداء وتغنيك عن البدء من نقطة الصفر مما يوفر لك الجهد والوقت.
</p>

<h2>
	مجالات وتطبيقات لغة جافا سكريبت
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="132576" href="https://academy.hsoub.com/uploads/monthly_2023_08/114973132_.png.7068266ed00ad606e3845e64f7a4cfbb.png" rel=""><img alt="تطبيقات جافا سكريبت.png" class="ipsImage ipsImage_thumbnailed" data-fileid="132576" data-ratio="57.17" data-unique="60lxxrqjv" style="width: 600px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_08/.thumb.png.5c9f95c121b291cf587a8cf866e43fd4.png"></a>
</p>

<p>
	قد تتساءل عن المجالات المختلفة التي يوفرها لك تعلم لغة جافا سكريبت، والخبر الجيد أن لغة جافا سكريبت هي لغة متعددة الاستخدامات، بالتالي تعلمها سيفتح لك مجالات عديدة يمكنك التخصص بها ويمكّنك من صنع أي نوع من التطبيقات.
</p>

<p>
	لنستعرض معًا أمثلةً على أهم استخدامات جافا سكريبت:
</p>

<ul>
	<li>
		تطوير مواقع الويب
	</li>
	<li>
		تطوير تطبيقات الجوال
	</li>
	<li>
		تطوير تطبيقات سطح المكتب
	</li>
	<li>
		برمجة الألعاب
	</li>
	<li>
		مواقع العروض التقديمية
	</li>
	<li>
		الذكاء الاصطناعي وتعلم الآلة
	</li>
	<li>
		تطوير التطبيقات القائمة على السحابة
	</li>
</ul>

<p>
	دعونا نتعرف على مزيد من التفاصيل حول كل مجال من هذه المجالات ومساهمة جافا سكريبت فيه.
</p>

<h3>
	تطوير مواقع الويب
</h3>

<p>
	تستخدم جافا سكريبت خاصةً في مجال تصميم وتطوير مواقع الويب، سواءً تطوير الواجهات الأمامية، أو الخلفية للمواقع، حيث تُعَد جافا سكريبت أفضل لغة برمجة لتطوير الواجهة الأمامية، وهي تضمَّن في كود HTML وتنفذ في المتصفح لتمنح الموقع وظائف إضافية وتأثيرات بصرية جذابة واحترافية، مع إضافة سلوك تفاعلي إلى صفحات الموقع لا يمكنك تحقيقها بواسطة HTML و CSS وحدها.
</p>

<p>
	أيضًا، توفر جافا سكريبت العديد من أطر العمل والمكتبات التي تساعد كثيرًا في تطوير الواجهة الأمامية للموقع، وأبرزها جي كويري jQuery وأنغولار Angular ورياكت React وفيو Vue وأمبر Ember.
</p>

<p>
	تستخدم جافا سكريبت أيضَا لتطوير الواجهة الخلفية لمواقع وتطبيقات الويب من خلال بيئة التشغيل <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-nodejs-r1463/" rel="">Node.js</a>، التي تعتمد على لغة جافا سكريبت الأساسية وتوفر الأدوات اللازمة لتشغيل جافا سكريبت على الخوادم ومعالجة الطلبات المختلفة من المتصفحات. ومن أهم أطر العمل التي تساعد في تطوير الواجهات الخلفية، نذكر Backbone واكسبرس <a href="https://academy.hsoub.com/programming/javascript/nodejs/express/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-nodejs-%D9%88%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-express-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-r1441/" rel="">Express </a>و Meteor و Sails …إلخ.
</p>

<p>
	بعد تحديد الإطار أو المكتبة التي ستستخدمها في الواجهة الخلفية، عليك اختيار قاعدة البيانات المناسبة لمشروعك، وأمامك مجموعة خيارات للتعامل معها فجافا سكريبت تدعم معظم <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">أنواع قواعد البيانات</a> مثل MySQL و MongoDB و PostgreSQL و MongoDB …إلخ.
</p>

<p>
	لعلك تكون قد استنتجت مما سبق أن تعلم جافا سكريبت يمكّنك من العمل كمطور ويب شامل Full Stack Developer، مما يكسبك الرهان في سوق العمل التنافسي، فجافا سكريبت ستكفيك بالتأكيد ولن تضطر معها إلى تعلم بنية لغات البرمجة الخلفية الأخرى، مثل روبي أو جافا أو بايثون، أو غيرهم. وللمزيد من المعلومات حول تطوير الويب الكامل، يمكنك مطالعة <a href="https://youtu.be/XqhWutUP5qY" rel="external nofollow">هذا الفيديو</a>.
</p>
<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			أنشئ موقع احترافي لأعمالك وعزّز حضورك الرقمي
		</p>

		<p class="banner-subtitle">
			صمم موقع إلكتروني فريد وجذاب لعملائك في دقائق دون خبرة برمجية باستخدام سنديان منشئ المواقع العربي
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://sndian.com/?utm_source=academy.hsoub.com&amp;utm_medium=referral&amp;utm_campaign=cademy.hsoub.com-CTA-Block" rel="external">أطلق موقعك الآن</a>
		</div>
	</div>
</div>


<h3>
	تطوير تطبيقات الجوال
</h3>

<p>
	إذا كنت مهتمًا بأن تصبح مطور تطبيقات جوال، فإن تعلم لغة جافا سكريبت سيمكنك من تطوير تطبيقات الهاتف المحمول المختلفة، سواءً التطبيقات الهجينة التي تتطلب منك كتابة كود التطبيق مرةً واحدةً فقط وتشغيله على مختلف الأنظمة مثل أندرويد Android وآي أو إس iOS (أبرز أطر عمل جافا سكريبت لتطوير تطبيقات الجوال الهجينة نذكر إطار أيونيك Ionic و PhoneGap و NativeScript)؛ أو تطوير تطبيقات جوال أصيلة native تعمل على الأنظمة المختلفة دون أي جهد إضافي لاستخدام قاعدة بيانات مختلفة لكل نظام من خلال إطار عمل React Native المبني بالاعتماد على مكتبة React.js.
</p>

<p>
	كذلك، يُعَد تطوير تطبيقات الويب التقدمية PWAs أحد أبرز مجالات لغة جافا سكريبت، وهي تطبيقات يمكن تشغيلها في المتصفح كموقع ويب أو تطبيق ويب، كما يمكن بذات الوقت تشغيلها على سطح المكتب والأجهزة المحمولة، وهذا بالاعتماد على قاعدة بيانات واحدة.
</p>

<p>
	تستخدم هذه التطبيقات تقنيات متطورةً توسع تطبيقات الويب وتحسن تجربة المستخدم، ويمكنك مطالعة مزيد من التفاصيل حول هذه التطبيقات وآلية عملها بقراءة مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">مدخل إلى تطبيقات الويب التقدمية PWA</a>.
</p>

<h3>
	تطوير تطبيقات سطح المكتب
</h3>

<p>
	توفر جافا سكريبت إطار عمل مفتوح المصدر يسمى إلكترون Electron يساعد المطورين كثيرًا على <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B3%D8%B7%D8%AD-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8/" rel="">تطوير تطبيقات سطح المكتب</a> باستخدام HTML5 و CSS وجافاسكريبت JavaScript، ويمكن لهذه التطبيقات العمل على كافة أنظمة التشغيل سواء ويندوز أو لينكس أو ماك. ويُعَد محرر الأكواد فيجوال ستوديو كود Visual Studio Code أحد الأمثلة الشهيرة على تطبيق سطح مكتب مبني باستخدام إطار العمل إلكترون Electron.
</p>

<h3>
	برمجة الألعاب
</h3>

<p>
	تُعَد لغة جافا سكريبت من التقنيات البارزة في مجال تطوير الألعاب ثنائية الأبعاد أو ثلاثية الأبعاد، سواءٌ الألعاب التي تعمل على الويب، أو على الجوال. فلعبة Angry Birds الشهيرة من أولى ألعاب الجوال المطورة باستخدام جافا سكريبت.
</p>

<p>
	وتوفر جافا سكريبت عشرات المكتبات والأطر ومحركات الألعاب التي تسرع عملية تطوير الألعاب وتمكّنك من إنشاء تأثيرات بصرية احترافية، نذكر منها مكتبة Three.js التي تمكنك من إنشاء رسومات احترافية ثلاثية الأبعاد في المتصفحات التي تدعم HTML5 ومحرك PixiJS و ImpactJS لتطوير الألعاب ثنائية الأبعاد و<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">محرك الألعاب</a> Phaser و BabylonJS لإنتاج رسوم متحركة وعوالم احترافية للألعاب ثلاثية الأبعاد.
</p>

<h3>
	مواقع العروض التقديمية
</h3>

<p>
	تُعَد جافا سكريبت مثاليةً لإنشاء مجموعة شرائح أو عروض تقديمية تستند إلى الويبو، أو ما يعرف باسم موقع ويب كعرض تقديمي Presentations as websites، حيث توفر جافا سكريبت مكتبات متخصصة في هذا الأمر مثل RevealJs و BespokeJs التي تسهل عليك مهمة إنشاء عرض تقديمي احترافي يعمل على شبكة الانترنت بسرعة وسهولة.
</p>

<h3>
	الذكاء الاصطناعي وتعلم الآلة
</h3>

<p>
	إذا كنت مهتمًا بمجال <a href="https://academy.hsoub.com/programming/artificial-intelligence/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B3%D8%B1%D9%8A%D8%B9%D8%A9-%D8%B9%D9%84%D9%89-%D9%85%D8%AC%D8%A7%D9%84-%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A2%D9%84%D8%A9-r1933/" rel="">تعلم الآلة Machine Learning</a> والتعلم العميق والشبكات العصبية Deep Learning، فإن لغة جافا سكريبت توفر لك مجموعةً من المكتبات المفيدة في هذا المجال، ومن أبرز هذه المكتبات JavaScript ML5.js و Synaptic و Brain.js و ConvNetJS.
</p>

<p>
	أيضًا، توفر لغة جافا سكريبت العديد من المكتبات المتعلقة بعلوم البيانات مثل مكتبة Tensorflow التي تسمح لعلماء البيانات بإنشاء رسوم بيانية لعرض البيانات.
</p>

<h3>
	تطوير التطبيقات القائمة على السحابة
</h3>

<p>
	يتجه معظم المطورين اليوم لاستخدام بيئة Node.js لبناء تطبيقات <a href="https://academy.hsoub.com/devops/cloud-computing/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%AD%D9%88%D8%B3%D8%A8%D8%A9-%D8%A7%D9%84%D8%B3%D8%AD%D8%A7%D8%A8%D9%8A%D9%91%D8%A9-%D8%A7%D9%84%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D9%91%D8%A9%D8%8C-%D9%88%D9%83%D9%8A%D9%81-%D8%AA%D8%B5%D8%A8%D8%AD-%D9%85%D9%87%D9%86%D8%AF%D8%B3-%D8%AD%D9%88%D8%B3%D8%A8%D8%A9-%D8%B3%D8%AD%D8%A7%D8%A8%D9%8A%D9%91%D8%A9-r457/" rel="">الحوسبة السحابية</a>، وهذه التطبيقات تعتمد في الغالب على قواعد البيانات غير العلائقية <a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D9%82%D9%86%D9%8A%D8%A9-nosql%D8%9F-r640/" rel="">NoSQL</a> لتخزين السجلات وتستخدم المعيار JSON من أجل تبادل البيانات على الإنترنت. وعلى الرغم من أن JSON يعمل جيدًا مع أي لغة برمجة، إلا أنه يعمل بصورة أفضل مع لغة JavaScript.
</p>

<p>
	كانت هذه أمثلة عن أبرز المجالات والتطبيقات التي ستتمكن من القيام بها عند تعلم جافا سكريبت، وهناك العديد من التطبيقات الأخرى، مثل تطبيقات قواعد البيانات وحلول إنترنت الأشياء IOT وتطبيقات الأمن السيبراني وغيرها.
</p>

<p style="text-align: center;">
	<img alt="مجالات javascript .png" class="ipsImage ipsImage_thumbnailed" data-fileid="132570" data-unique="g3vegzsft" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_08/javascript.thumb.png.373a0f5cf17582ea39073762bab86c94.png">
</p>

<p>
	وكما ترى، لغة جافا سكريبت هي لغة برمجة قوية وشاملة ومتعددة الاستخدام وتتميز عن غيرها من لغات البرمجة بتنوع مجالاتها وبكونها صالحة لبناء أي نوع من التطبيقات، لذا كل ما عليك هو تحديد المجال الذي تريد التخصص فيه وستجد الكثير من الأطر والمكتبات التي توفرها لك لغة جافا سكريبت، والتي تسهل عليك إنجاز هذه التطبيقات بسرعة ومرونة.
</p>

<h2>
	ما الفرق بين جافا وجافا سكريبت
</h2>

<p style="text-align: center;">
	<img alt="الفرق بين جافا وجافا سكريبت.png" class="ipsImage ipsImage_thumbnailed" data-fileid="132566" data-unique="qta2wqe6t" style="width: 400px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_08/.thumb.png.be928cab544ee4a4f621044a1735c39d.png">
</p>

<p>
	على الرغم من أن لغة جافا ولغة جافا سكريبت تتشابهان في التسمية وتناسبان تطوير تطبيقات الويب وتطبيقات الجوال، إلا أنهما <strong>لغتان مختلفان تمامًا</strong> ولا ينبغي الخلط بينهما، فقد طورت جافا سكريبت عام 1995 من قبل Netscape Communications على أنها -لغة برمجة نصية- تتوافق مع مواصفات ECMAScript، وتسمح بتحديد سلوك الصفحة من طرف العميل وتنفيذ أمور متقدمة على صفحات الويب وتجعلها أكثر ديناميكية وتفاعلية؛ أما لغة جافا فهي لغة تم تطويرها عام 1995 من قِبل شركة Sun Microsystems لتكون -لغة برمجة عامة الأغراض-.
</p>

<p>
	أيضًا، تعتمد لغة جافا سكريبت على البرمجة القائمة على الأحداث وتدعم نموذج <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A5%D8%AC%D8%B1%D8%A7%D8%A6%D9%8A%D8%A9/" rel="">البرمجة الإجرائية</a> والبرمجة كائنية التوجه لبناء صفحات ويب تفاعلية، وتوفر واجهات برمجة تطبيقات للعمل مع النصوص والتواريخ وهياكل البيانات ونموذج كائن المستند DOM؛ في حين تعتمد لغة جافا أساسًا على مفهوم الكائنات Objects و<a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/" rel="">البرمجة كائنية التوجه <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr></a>، ويمكن تشغيل التعليمات البرمجية المكتوبة فيها على أي نظام تشغيل، من خلال آلة جافا الافتراضية Java virtual machine أواختصارًا JVM.
</p>

<p>
	وبالتالي يمكن القول أن كلًا من لغة جافا وجافا سكربيت تستخدمان في العديد من المجالات، مثل تطوير الويب وتطوير تطبيقات الهاتف المحمول وتطبيقات سطح المكتب وإنترنت الأشياء والأنظمة المضمنة وغيرها من المجالات، لكن الاختلاف الأساسي بينهما يكمن في نموذج البرمجة الخاص بكل منهما، فلغة جافا تعتمد على مفهوم الكائنات <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr>، في حين أن لغة جافا سكريبت متعددة النماذج، حيث يمكن استخدامها كلغة <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr>، أو لغة إجرائية، أو لغة نصية.
</p>

<p>
	كذلك، تختلف الللغتان في طريقة تنفيذ التعليمات البرمجية، حيث تشغّل تعليمات جافا سكريبت على المتصفح ولها تطبيقات قادرة على تنفيذها خارج المتصفح من جانب الخادم، في حين يتم تنفيذ أكواد جافا على آلة جافا الافتراضية JVM أو على متصفح يدعم جافا من خلال ما يعرف ببريمجات جافا Java applet.
</p>

<h2>
	ما الفرق بين لغة جافا سكريبت JavaScript ولغة تايب سكريبت Typescript؟
</h2>

<p style="text-align: center;">
	<img alt="الفرق بين javascript و typescript.png" class="ipsImage ipsImage_thumbnailed" data-fileid="132565" data-unique="ne59lfn3j" style="width: 400px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_08/javascripttypescript.thumb.png.5e060f7b1343b484204ee7702dd34a10.png">
</p>

<p>
	بالرغم من أن جافا سكريبت هي لغة البرمجة النصية الأكثر شيوعًا واستخدامًا في مواقع وتطبيقات الويب، إلا أنها ليست اللغة الوحيدة التي تقوم بذلك، حيث تُعَد لغة تايب سكريبت <a href="https://academy.hsoub.com/programming/javascript/typescript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-typescript-r1214/" rel="">TypeScript</a> كذلك لغةً برمجةً نصية مفتوحة المصدر طورتها شركة مايكروسوفت عام 2012، وكان الهدف من إيجادها هو أن كود جافا سكريبت قد أصبح معقدًا وصار التعامل معه صعبًا في التطبيقات الكبيرة.
</p>

<p>
	على هذا الأساس تم إستحداث لغة TypeScript التي تُعَد لغةً برمجةً نصيةً تساعد في إنشاء محتوى صفحة ويب ديناميكي، وهي لغة أشمل من جافا سكريبت وتتبع نفس معاييرها ECMAScript وتتوافق مع مكتباتها، ولكنها تجعل من جافا سكريبت أسهل في الإدارة والتعامل.
</p>

<p>
	تضيف TypeScript المزيد من الميزات على جافا سكريبت، ومن أبرزها دعم الأنواع Types، مما يجعل من بناء التعليمات البرمجية أكثر وضوحًا وفهمًا وتسهيلًا لعملية تصحيح الأخطاء والكشف المبكر عنها أثناء ترجمة أو تصريف الكود، وللعلم كل ما تكتبه في TypeScript يحوّل في النهاية إلى لغة جافا سكريبت، بالتالي إذا حفظت ملف جافا سكريبت ذي الامتداد js. بامتداد ts. الخاص بلغة TypeScript فسيعمل جيدًا، لكن تجدر الإشارة بأنه لا يمكنك تشغيل كود TypeScript مباشرةً في المتصفح، بل تحتاج إلى بيئة تشغيل مثل NodeJs لتحويل التعليمات البرمجية.
</p>

<p>
	يمنحك تعلم TypeScript كمبرمج قوةً إضافية، فهو يمكّنك من العمل على كل من مشاريع جافا سكريبت و TypeScript بذات الوقت، وستجد في أكاديمية حسوب <a href="https://academy.hsoub.com/programming/javascript/typescript/" rel="">مجموعة مقالات منوعة عن أساسيات TypeScript</a>، كما توفر موسوعة حسوب <a href="https://wiki.hsoub.com/TypeScript" rel="external">توثيق Typescript شاملًا</a> يعرّفك على كل ما يتعلق بهذه اللغة.
</p>

<p>
	ويمكن القول باختصار بأن لغة جافا سكريبت هي الخيار الأنسب عند العمل على مشاريع ويب صغيرة، في حين أن TypeScript مناسبة للعمل على المشاريع المعقدة. ولمطالعة من التفاصيل حوال أبرز الفروقات بين هاتين اللغتين، أنصحك بمطالعة مقال <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-javascript-%D9%88-typescript-r1598/" rel="">مقارنة بين JavaScript و TypeScript</a>
</p>

<h2>
	خطوات تعلم لغة جافا سكريبت
</h2>

<p>
	هل ترغب في تعلم لغة جافا سكريبت ولكنك لا تعرف من أين تبدأ؟ أو ربما قد بدأت في تعلمها بالفعل لكنك تشعر أنك تتقدم ببطء وتبحث عن أفضل الطرق لتعلم لغة جافا سكريبت والبدء بتطوير التطبيقات المتنوعة من خلالها؟
</p>

<p>
	حسنًا، يجب أن تضع في الحسبان أن أمامك مستويين من التعلم. الأول هو تعلم لغة جافا سكريبت نفسه، والثاني هو تعلم الأدوات والأطر الخاصة بلغة جافا سكريبت، والتي يمكنك إتقان أي منها والاستفادة من قوتها دون الحاجة للغوص في كل تفاصيل اللغة. وفيما يلي نقترح لك مجموعة من الخطوات التي تساعدك على تعلم جافا سكريبت بسرعة وكفاءة:
</p>

<h3>
	الخطوة 1. تعلم أساسيات جافا سكريبت
</h3>

<p>
	بالرغم من أن جافا سكريبت توفر العديد من المكتبات والأطر التي تتضمن شيفرات جاهزة للاستخدام تغنيك عن تعلم جافا سكريبت من البداية وتختصر لك الكثير من العمل، إلا أنني أنصحك بأن تبدأ بتعلم المبادئ الأساسية للويب وأساسيات لغة جافا سكريبت نفسها قبل الاعتماد على الأطر، فهذا سيساعدك بأن تصبح مطورًا محترفًا ويسرع من فهم إطار العمل الذي تنوي استخدامه بشكل أفضل، كما يسرع من فهم وصيانة التطبيقات والبرامج التي تطورها.
</p>

<h3>
	الخطوة 2. تعلم المكتبات والأطر المساعدة
</h3>

<p>
	بمجرد أن تتقن أساسيات جافا سكريبت، يمكنك التركيز على تعلم أطر العمل والمكتبات التي تساعدك في تحقيق أهدافك، فإذا كان هدفك هو تطوير الواجهة الأمامية لمواقع الويب، فركز على تعلم أدواتها. وإذا كان هدفك هو تطوير تطبيقات الجوال، فابدأ بتعلم أهم الأطر والمكتبات التي تساعدك في تحقيق هدفك.
</p>

<h3>
	الخطوة 3. طبق ما تعلمته على مشاريع عملية
</h3>

<p>
	لاشك أن أفضل طريقة لإتقان أي لغة برمجة ومن بينها جافا سكريبت هي التدريب العملي ومحاولة بناء مشاريع وتطبيقات تحل مشكلات حقيقية كي تعزز معلوماتك النظرية، بالتالي بمجرد أن تكمل تعلم أساسيات جافا سكريبت وأساسيات الأطر التي تحتاجها لبناء مشاريعك، ابدأ بتجريب ما تعلمته على مشاريع عملية. ويمكنك الاطلاع على مشاريع مفتوحة المصدر والاطلاع على الشيفرة البرمجية الخاصة به ومحاولة فهمها وتعديلها وتحسينها.
</p>

<h3>
	الخطوة 4. كن صبورا في التعامل مع المشكلات البرمجية
</h3>

<p>
	عندما تبني مشاريع عملية، سوف تواجه العديد من الأخطاء والمشكلات بلا شك، وهذا أمر مرهق في البداية، لكن عليك أن تتحلى بالصبر وأن تكتسب مهارة حل المشكلات وطرح الأسئلة والبحث عن الحلول بنفسك، فهذا سيساعدك كثيرًا على تحسين مهاراتك في البحث ومرونة في حل المشكلات البرمجية، وهما صفتان هامتان لك كمطور، وبنفس الوقت يساعدك التعلم من خلال المشاريع في بناء ملف تعريف شخصي يتيح لك الحصول على فرصة عمل مناسبة.
</p>

<h3>
	الخطوة 5. ركز على المصادر الجيدة للتعلم
</h3>

<p>
	لا شك أن هناك الكثير من موارد التعلم الخاصة بجافا سكريبت JavaScript من كتب ومقالات ومعسكرات وبودكاست ودورات تشرح ماهية جافا سكريبت وأطر عملها المختلفة، ويمكنك الاعتماد عليها في الويب في عملية التعلم الذاتي؛ لكن انتبه كي لا تتشتت خلال تعلمك، واحرص على الاعتماد على مصادر منهجية ومنظمة وركز على أسلوب التعلم المفضل لديك.
</p>

<p>
	وفي هذا الصدد، يمكن الإشارة إلى أن أكاديمية حسوب وفرت مجموعةً مميزةً من <a href="https://academy.hsoub.com/programming/javascript/" rel="">مقالات تعلم جافا سكريبت</a> وأطر عملها المختلفة، يمكنك الوصول لها من خلال الرابط التالي؛ كما توفر موسوعة حسوب <a href="https://wiki.hsoub.com/JavaScript" rel="external">توثيقًا مميزًا لجافا سكريبت</a> شاملًا وعالي الجودة ومرفق بالأمثلة العملية يساعدك في تعلم اللغة من الصفر.
</p>

<p>
	أيضًا، أصدرت أكاديمية حسوب عدة كتب شاملة تساعدك أي مبتدئ يشق طريقه في هذه اللغة هي كتاب <a href="https://academy.hsoub.com/files/33-%D8%AF%D9%84%D9%8A%D9%84-javascript-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84/" rel="">دليل JavaScript الشامل</a> و<a href="https://academy.hsoub.com/files/27-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA/" rel="">البرمجة بلغة جافاسكربت</a> و<a href="htps://academy.hsoub.com/files/32-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-nodejs/" rel="">البرمجة باستخدام Node.js</a>، فإذا كنت تفضل التعلم عن طريق الكتب لما توفره من معلومات دقيقة ومترابطة، فأنصحك بتحميل هذه الكتب واعتمادها كمراجع في التعلم.
</p>

<p>
	وإذا كنت تبحث عن دورة تدريبية احترافية توفر وقتك ومواردك وتمكنك من تعلم جافا سكريبت واحتراف تطوير التطبيقات المختلفة باستخدامها ودخول سوق العمل بسرعة، فيمكنك الاطلاع على <a href="https://academy.hsoub.com/learn/javascript-application-development/" rel="">دورة تطوير التطبيقات باستخدام لغة JavaScript</a> التي توفرها أكاديمية حسوب، والتي تتضمن 55 ساعة فيديو تدريبية أعدها نخبة من المتخصصين، وهي دورة غنية تتضمن عدة مسارات ولا تتطلب منك أي معرفة مسبقة للبدء، كما وتوفر لك إمكانية الحصول على شرح تفصيلي وتحديثات دورية ودعم فوري وإجابة على كافة التساؤلات التي تواجهك خلال رحلة تعلمك وتضمن لك في النهاية الحصول على شهادة معتمدة من أكاديمية حسوب.
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="442" id="ips_uid_8115_6" src="https://academy.hsoub.com/applications/core/interface/index.html" title="دورة تطوير التطبيقات باستخدام JavaScript - أكاديمية حسوب" width="786" data-embed-src="https://www.youtube.com/embed/T6CnMmvF4e0"></iframe>
</p>

<h2>
	الخلاصة
</h2>

<p>
	إلى هنا نكون قد وصلنا لنهاية مقالنا الشامل، والذي تناولنا فيه كل ما يتعلق بلغة جافا سكريبت JavaScript واستعرضنا تاريخ تطورها وتعرفنا على أطر عمل جافا سكريبت التي تعطي لها قوةً إضافية وتمكنها من التوسع في مجالات عديدة وتحولها من لغة مقتصرة على العمل في المتصفح إلى لغة قوية وشاملة ومتعددة المجالات ومفضلة بين مجتمع المطورين ومهندسي البرمجيات حول العالم.
</p>

<p>
	والآن هل أنت مهتم بتعلم جافا سكريبت أو لديك أي تساؤل حولها؟ يمكنك كتابة سؤالك في قسم التعليقات أسفل المقال وإذا كنت قد بدأت بالفعل في تعلم جافا سكريبت واستخدامها في التطبيقات العملية، فشاركنا تجربتك وأخبرنا عن العقبات التي واجهتها خلال تعلم جافا سكريبت وأبرز الإيجابيات والسلبيات التي لاحظتها عند استخدامك لهذه اللغة.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/javascript/" rel="">الدليل الشامل لتعلم جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1689/" rel="">أساسيات لغة جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D8%9F-r524/" rel="">ما هي جافا سكريبت؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">الدليل السريع إلى لغة البرمجة جافاسكريبت JavaScript</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-object-oriented-javascript-r179/" rel="">مدخل إلى جافاسكريبت كائنية التوجه</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B3%D8%B7%D8%AD-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8/" rel="">كل ما تود معرفته عن برمجة تطبيقات سطح المكتب</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2046</guid><pubDate>Thu, 10 Aug 2023 16:02:00 +0000</pubDate></item><item><title>&#x62A;&#x637;&#x648;&#x64A;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642; '&#x639;&#x644;&#x645;&#x646;&#x64A;' &#x644;&#x627;&#x633;&#x62A;&#x643;&#x634;&#x627;&#x641; &#x627;&#x644;&#x645;&#x648;&#x627;&#x636;&#x64A;&#x639; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A; &#x648; ChatGPT</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%84%D9%85%D9%86%D9%8A-%D9%84%D8%A7%D8%B3%D8%AA%D9%83%D8%B4%D8%A7%D9%81-%D8%A7%D9%84%D9%85%D9%88%D8%A7%D8%B6%D9%8A%D8%B9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%88-chatgpt-r2031/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_07/----------ChatGPT.png.93a4cc3dcf1e74dbb0b03e08808e2bbd.png" /></p>
<p>
	عند التعرف على موضوع جديد والقراءة عنه نبدأ عادة بالبحث عن تعريف يشرح ويوضح الصورة العامة له، ثم نكتشف مجموعة من المواضيع الأخرى الفرعية المتعلقة بالموضوع الأساسي، وعادة ما نبدأ البحث عبر الإنترنت عبر ويكيبيديا مثلًا، ونقرأ ونستكشف المواضيع بين صفحة وأخرى.
</p>

<p>
	لكن ماذا لو كان هناك أداة تساعدنا في ذلك فتولد مواضيع فرعية من الموضوع الرئيسي أو المواضيع الفرعية عنه وتشرح كل منها، هذا ما سنطوره في هذا المقال ومصدر تلك المعلومات سيكون أحد نماذج الذكاء الاصطناعي وهو <a href="https://academy.hsoub.com/apps/web/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A8%D9%88%D8%AA-%D8%A7%D9%84%D9%85%D8%AD%D8%A7%D8%AF%D8%AB%D8%A9-%D8%A7%D9%84%D8%B0%D9%83%D9%8A-%D8%B4%D8%A7%D8%AA-%D8%AC%D9%8A-%D8%A8%D9%8A-%D8%AA%D9%8A-chatgpt-r863/" rel="">ChatGPT</a>.
</p>

<h2>
	هل يملك ChatGPT المعرفة
</h2>

<p>
	تٌحاكي نماذج اللغة الكبيرة (أو Large Language Models) ومنها ChatGPT البيانات التي دُّربت عليها، فإذا دُربت على نصوص متنوعة ستتمكن من محاكاة وتوليد نصوص مشابهة لها قد لا يُلاحظ الفرق بينها وبين الأصلية، ولكن لا يمكن الاعتماد على دقتها فتلك النماذج خصوصًا المُدربة على طيف واسع من البيانات تُحاكي فقط ما دُربت عليه ولا تملك فهم حقيقي كما نحن البشر عن تلك النصوص.
</p>

<p>
	فكثيرًا من الأحيان سيخطئ النموذج بثقة، لذا لا يمكننا الاعتماد دومًا على معلوماته، إنما في هذا المقال سنطور تطبيق لتوليد معلومات عامة وبسيطة ليست دقيقة أو معقدة، فمثل تلك المعلومات قد وردت ضمن البيانات التي دُرب عليها ChatGPT كثيرًا ومن أكثر من رأي وزاوية، لذا يمكننا الاعتماد عليه في حال كانت المعلومات بسيطة وغير معقدة مع الحذر دومًا والتحقق من صحة المعلومات الحساسة.
</p>

<h2>
	أفكار لمشاريع باستخدام ChatGPT
</h2>

<p>
	بسبب سهولة التعامل مع نموذج ChatGPT والطيف الواسع من الإمكانيات يمكن الاستفادة من مثل تلك النماذج في بناء العديد من التطبيقات بأفكار متنوعة، فمثلًا تلخيص مقال طويل يستفيد منه المستخدم في الاطلاع على محتوى المقال بسرعة قبل قراءته كما فعلنا في <a href="https://academy.hsoub.com/programming/php/laravel/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%84%D8%AE%D8%B5%D9%84%D9%8A-%D9%84%D8%AA%D9%84%D8%AE%D9%8A%D8%B5-%D8%A7%D9%84%D9%85%D9%82%D8%A7%D9%84%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-chatgpt-%D9%88%D9%84%D8%A7%D8%B1%D8%A7%D9%81%D9%84-r2008/" rel="">تطبيق لخصلي</a> في مقال سابق، أو يمكن طلب اقتراح وصفة طعام معينة وشرح طريقة تحضيرها والاستفادة من المعلومات الكامنة ضمن النموذج والذي اكتسبها أثناء مرحلة التدريب كما فعلنا في <a href="https://academy.hsoub.com/programming/php/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D8%B5%D9%81%D8%A9-%D9%84%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%AD-%D8%A7%D9%84%D9%88%D8%AC%D8%A8%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-chatgpt-%D9%88-dall-e-%D9%81%D9%8A-php-r2005/" rel="">تطبيق وصفة</a> في مقال آخر سابق، أو يمكن طلب تصحيح نص ما أدخله المستخدم والاستفادة منه كمصحح نصوص آلي، أو يمكن طلب استخراج الكلمات المفتاحية من نص معين والذي يفيد في العديد من المجالات من تخزين البيانات إلى مساعدة كُتّاب المقالات وغيرها.
</p>

<p>
	أما في هذا المقال سنتعرف على طريقة الاستعانة بنموذج ChatGPT لتوليد مواضيع في مجالات مختلفة والغوص في مواضيع فرعية عنها، وسوف نستفيد من المعرفة التي يملكها ChatGPT وتدرب عليها مسبقًا، وذلك بتطوير تطبيق بسيط يعرض للمستخدم بعض الأفكار العشوائية ليختار أحدها ثم نتفرع إلى مواضيع فرعية مع شرح بسيط عنها، ثم سنجعل ChatGPT يختار موضوع فرعي لنولد منه مواضيع فرعية أيضًا وهكذا يستفيد المستخدم من التطبيق في استكشاف الأفكار وتفاصيلها.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة تطوير التطبيقات باستخدام لغة JavaScript
		</p>

		<p class="banner-subtitle">
			تعلم البرمجة بلغة جافا سكريبت انطلاقًا من أبسط المفاهيم وحتى بناء تطبيقات حقيقية.
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/javascript-application-development/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<img alt="دورة تطوير التطبيقات باستخدام لغة JavaScript" src="https://academy.hsoub.com/learn/assets/images/courses/javascript-application-development.png">
	</div>
</div>

<h2>
	تحضير صفحات التطبيق
</h2>

<p>
	نبدأ بإنشاء مجلد جديد لملفات المشروع ونُنشئ ملف <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> بالاسم index.html ونستورد ضمنه ملف <a href="https://wiki.hsoub.com/jQuery" rel="external">مكتبة jQuery</a> والتي سنستخدمها لتعديل محتويات الصفحة، وملف <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافا سكريبت</a> باسم script.js والذي سيحوي شيفرة التطبيق، وملف <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> يتضمن التنسيقات style.css كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1960_6" style=""><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"ar"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"UTF-8"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"viewport"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"width=device-width, initial-scale=1.0"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://code.jquery.com/jquery-3.7.0.min.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"script.js"</span><span class="pln"> </span><span class="atn">defer</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
    </span><span class="tag">&lt;link</span><span class="pln"> </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"stylesheet"</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"style.css"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">علمني</span><span class="tag">&lt;/title&gt;</span><span class="pln">
  </span><span class="tag">&lt;/head&gt;</span><span class="pln">
  </span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;div&gt;</span><span class="pln">
      </span><span class="tag">&lt;h1&gt;&lt;/h1&gt;</span><span class="pln">
      </span><span class="tag">&lt;p&gt;&lt;span&gt;</span><span class="pln">?</span><span class="tag">&lt;/span&gt;</span><span class="pln"> اختر أحد المواضيع لمعرفة المزيد</span><span class="tag">&lt;/p&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	كما تلاحظ في الكود أعلاه تحتوي الصفحة على عنصر <code>&lt;div&gt;</code> بالمٌعرّف container وضمنه سنضيف محتوى المواضيع الأساسية والمواضيع الفرعية.
</p>

<p>
	بعد ذلك سوف ننشئ ملف التنسيقات style.css ضمن مجلد المشروع وسنكتب ضمنه التنسيقات التالية:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_1182_6" style=""><span class="pln">body </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">direction</span><span class="pun">:</span><span class="pln"> rtl</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">flex-direction</span><span class="pun">:</span><span class="pln"> column</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">max-width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">60ch</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">justify-items</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">align-items</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">font-size</span><span class="pun">:</span><span class="pln"> x-large</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> auto</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20vh</span><span class="pln"> </span><span class="lit">10vw</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">background-color</span><span class="pun">:</span><span class="pln"> </span><span class="lit">#f9f9f9</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">color</span><span class="pun">:</span><span class="pln"> </span><span class="lit">#121212</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">font-family</span><span class="pun">:</span><span class="pln"> system-ui</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">align-items</span><span class="pun">:</span><span class="pln"> stretch</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">gap</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

p </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">line-height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">color</span><span class="pun">:</span><span class="pln"> darkslategray</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

a </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">font-size</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inherit</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">.5rem</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">color</span><span class="pun">:</span><span class="pln"> darkblue</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

footer </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">margin-top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

form </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">flex-direction</span><span class="pun">:</span><span class="pln"> column</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">gap</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2rem</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">text-align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

button </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">background-color</span><span class="pun">:</span><span class="pln"> </span><span class="lit">#121212</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">color</span><span class="pun">:</span><span class="pln"> </span><span class="lit">#f9f9f9</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">border</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> </span><span class="lit">2rem</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">font-size</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inherit</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">font-family</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inherit</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

input </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> </span><span class="lit">2rem</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">font-size</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inherit</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">font-family</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inherit</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">text-align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">.2rem</span><span class="pln"> solid</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">subject </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2rem</span><span class="pln"> </span><span class="lit">2rem</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">.15rem</span><span class="pln"> solid lightgray</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">border-radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">.5rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">#</span><span class="pln">container </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">gap</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2rem</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">flex-direction</span><span class="pun">:</span><span class="pln"> column</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لمعاينة شكل الموقع نضيف بعض المواضيع الوهمية يدويًا ضمن العنصر بالمعرّف container بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1960_12" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"subject"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;h2&gt;</span><span class="pln">الموضوع</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">شرح عن الموضوع</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	نفتح الصفحة index.html ضمن المتصفح ونلاحظ شكل الموقع بعد التنسيق:
</p>

<p style="text-align: center;">
	<img alt="index.png" class="ipsImage ipsImage_thumbnailed" data-fileid="130568" data-unique="ultn1paz5" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_07/index.thumb.png.6b41141e241e36f426adaa562d7f3582.png">
</p>

<h2>
	توليد وعرض مواضيع عشوائية للمستخدم
</h2>

<p>
	ننشئ ملف جافا سكريبت script.js ونبدأ بكتابة شيفرة التطبيق، وللتعامل مع الواجهة البرمجية لنموذج ChatGPT يجب توليد مفتاح الاستيثاق لها بعد إنشاء حساب مدفوع على موقع شركة OpenAI، ولكي نتجنب استخدام المفتاح الخاص بنا من قبل المستخدمين يمكننا الطلب من كل مستخدم إدخال مفتاحه الخاص عند أول استخدام للتطبيق وحفظه لاستخدامه لاحقًا عند الاتصال بالواجهة البرمجية للنموذج ChatGPT، حيث يسمح لنا ذلك بحرية أكبر في تطوير التطبيقات التي تعتمد على الذكاء الاصطناعي بلا أي كلفة.
</p>

<p>
	ولاستخدام ذلك المفتاح يجب حفظه في مكان آمن، وبما أننا لن نستخدم أي شيفرات جافاسكربت خارجية فسنخزن المفتاح ضمن <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%85%D8%AD%D9%84%D9%8A%D8%A7-%D9%81%D9%8A-%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1338/" rel="">التخزين المحلي لمتصفح الويب</a> الخاص بالمستخدم باستخدام الكائن <code>localStorage</code>، أما في حال استخدامك لأي شيفرات من مكتبات خارجية ضمن المشروع فيمكن لتلك الشيفرات قراءة المفتاح وسرقته من المستخدم، عندها يجب البحث عن حلول أخرى كتخزين المفتاح بأمان ضمن خادم المشروع والتعريف عن المستخدم بطريقة ما مثل استخدام <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D9%88%D8%B6%D8%A8%D8%B7%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1330/" rel="">ملفات تعريف الارتباط Cookies</a> وإرسال الطلبات من قبل الخادم بدلًا من قبل متصفح المستخدم نفسه، والآن نعرف التابع <code>openAIKey</code> والذي يتحقق وجود مفتاح مُخزن سابقًا ويعيده، وإلا يطلب من المستخدم إدخال مفتاحه باستخدام الدالة <code>prompt</code> وحفظ ذلك المفتاح للاستخدام لاحقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1960_14" style=""><span class="kwd">function</span><span class="pln"> openAIKey</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> localStorageKey </span><span class="pun">=</span><span class="pln"> </span><span class="str">'OPENAI_API_KEY'</span><span class="pun">;</span><span class="pln">

    </span><span class="com">// استخراج المفتاح المُخزن سابقًا</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> apiKey </span><span class="pun">=</span><span class="pln"> localStorage</span><span class="pun">.</span><span class="pln">getItem</span><span class="pun">(</span><span class="pln">localStorageKey</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">apiKey</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// طلب إدخال المفتاح من المستخدم</span><span class="pln">
        apiKey </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">'أدخل مفتاح OpenAI الخاص بك'</span><span class="pun">)</span><span class="pln">
        </span><span class="com">// تخزين المفتاح</span><span class="pln">
        localStorage</span><span class="pun">.</span><span class="pln">setItem</span><span class="pun">(</span><span class="pln">localStorageKey</span><span class="pun">,</span><span class="pln"> apiKey</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> apiKey
</span><span class="pun">}</span></pre>

<p>
	وللتعامل مع نموذج ChatGPT نُعرف التابع <code>chatGPT</code> والذي يقبل التعليمة التي سترسل له كمعامل أول، ويُرسل طلب من نوع POST إلى المسار <a href="https://api.openai.com/v1/chat/completions" ipsnoembed="false" rel="external nofollow">https://api.openai.com/v1/chat/completions</a> بحسب توثيق تلك الواجهة البرمجية وكما شرحناها في <a href="https://academy.hsoub.com/programming/php/laravel/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%84%D8%AE%D8%B5%D9%84%D9%8A-%D9%84%D8%AA%D9%84%D8%AE%D9%8A%D8%B5-%D8%A7%D9%84%D9%85%D9%82%D8%A7%D9%84%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-chatgpt-%D9%88%D9%84%D8%A7%D8%B1%D8%A7%D9%81%D9%84-r2008/" rel="">مقال سابق</a>، ثم نستخرج رد النموذج منه كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1960_16" style=""><span class="kwd">function</span><span class="pln"> chatGPT</span><span class="pun">(</span><span class="pln">prompt</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">// إرسال الطلب</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> fetch</span><span class="pun">(</span><span class="str">'https://api.openai.com/v1/chat/completions'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        method</span><span class="pun">:</span><span class="pln"> </span><span class="str">'POST'</span><span class="pun">,</span><span class="pln">
        headers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="str">'Content-Type'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'application/json'</span><span class="pun">,</span><span class="pln">
            </span><span class="com">// ترويسة الاستيثاق</span><span class="pln">
            </span><span class="str">'Authorization'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Bearer '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> openAIKey</span><span class="pun">(),</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        body</span><span class="pun">:</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">({</span><span class="pln">
            </span><span class="com">// اسم النموذج</span><span class="pln">
            </span><span class="str">"model"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"gpt-3.5-turbo"</span><span class="pun">,</span><span class="pln">
            </span><span class="com">// تعليمة المستخدم</span><span class="pln">
            </span><span class="str">"messages"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[{</span><span class="pln"> </span><span class="str">"role"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"content"</span><span class="pun">:</span><span class="pln"> prompt </span><span class="pun">}]</span><span class="pln">
        </span><span class="pun">}),</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
        </span><span class="com">// تفسير الطلب</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">json</span><span class="pun">())</span><span class="pln">
        </span><span class="com">// استخراج رد النموذج</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">json </span><span class="pun">=&gt;</span><span class="pln"> json</span><span class="pun">.</span><span class="pln">choices</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">message</span><span class="pun">.</span><span class="pln">content</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	باستخدام التابع <code>chatGPT</code> يمكننا الآن توليد محتوى الأفكار العشوائية الأولية التي ستظهر للمستخدم بإرسال التعليمة التالية إلى ChatGPT:
</p>

<pre class="ipsCode">اقترح بعض المواضيع لأتعلم عنها، المواضيع كل موضوع بسطر:
</pre>

<p>
	لاحظ أننا نحدد في نهاية التعليمة شكل الخرج الذي نريده وهو في هذه الحالة أن يكتب لنا كل موضوع بسطر، لنتمكن من استخراج تلك المواضيع بتقسيم الرد إلى الأسطر المكونة له، ثم تحويل كل سطر إلى كائن جافاسكربت يحتوي على الحقل <code>title</code> وهو عنوان الموضوع، نٌعرّف تلك العملية ضمن التابع <code>getInitialSubjects</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1960_18" style=""><span class="kwd">function</span><span class="pln"> getInitialSubjects</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> chatGPT</span><span class="pun">(</span><span class="str">'اقترح بعض المواضيع لأتعلم عنها، المواضيع كل موضوع بسطر:'</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">subjects </span><span class="pun">=&gt;</span><span class="pln"> subjects</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">'\n'</span><span class="pun">).</span><span class="pln">map</span><span class="pun">(</span><span class="pln">title </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> title </span><span class="pun">})))</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ولعرض تلك المواضيع نستخدم <a href="https://academy.hsoub.com/programming/javascript/jquery/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D9%91%D8%A7%D8%AA-jquery-r60/" rel="">مكتبة jQuery</a> لتحديد العنصر الذي سيحتوي المحتوى باستخدام التابع <code>$</code> وهو صاحب المٌعرّف container، ونفرغ محتواه باستخدام <code>empty</code> ونمر على كل كائن منها ونولد له عناصر تحوي على عنوان الموضوع من الحقل <code>title</code>، ونستخدم التابع <code>append</code> لإضافة تلك العناصر داخل بعضها، ونعرّف عملية عرض كائنات المواضيع ضمن التابع <code>renderSubjects</code> ليكون كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1960_20" style=""><span class="kwd">function</span><span class="pln"> renderSubjects</span><span class="pun">(</span><span class="pln">subjects</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// العنصر الحاوي</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> $container </span><span class="pun">=</span><span class="pln"> $</span><span class="pun">(</span><span class="str">'#container'</span><span class="pun">)</span><span class="pln">

    </span><span class="com">// مسح المحتوى السابق</span><span class="pln">
    $container</span><span class="pun">.</span><span class="pln">empty</span><span class="pun">()</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> subject </span><span class="kwd">of</span><span class="pln"> subjects</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// إنشاء عنصر الموضوع </span><span class="pln">
        </span><span class="kwd">const</span><span class="pln"> $subject </span><span class="pun">=</span><span class="pln"> $</span><span class="pun">(`&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"subject"</span><span class="pun">&gt;&lt;/</span><span class="pln">div</span><span class="pun">&gt;`)</span><span class="pln">

        </span><span class="com">// إضافة العنوان</span><span class="pln">
        $subject</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(`&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">$</span><span class="pun">{</span><span class="pln">subject</span><span class="pun">.</span><span class="pln">title</span><span class="pun">}&lt;/</span><span class="pln">h2</span><span class="pun">&gt;`)</span><span class="pln">

        </span><span class="com">// إضافة الموضوع إلى الحاوية</span><span class="pln">
        $container</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">$subject</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وبذلك أصبحت كل التوابع جاهزة من توليد الأفكار العشوائية إلى عملية عرضها، لذا في نهاية الملف نستدعي التابع <code>getInitialSubjects</code> ونمرر تابع عرض المواضيع <code>renderSubjects</code> إلى التابع <code>then</code> من ذلك التابع لعرض تلك المواضيع بعد جلبها، ونفتح الملف index.html ضمن المتصفح سنلاحظ طلب التطبيق منا لأول مرة إدخال مفتاح الواجهة البرمجية:
</p>

<p>
	[prompt.png]
</p>

<p>
	وبعد إدخال المفتاح الخاص بنا سيُرسل طلب توليد المواضيع إلى ChatGPT وتعرض النتائج كالتالي:
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="130569" data-unique="wonxk9byi" src="https://academy.hsoub.com/uploads/monthly_2023_07/main.thumb.png.c1c61896804b2c3e90c27eabc3a73948.png">
</p>

<p>
	نلاحظ تنوع المواضيع التي ولدها وكيف أمكننا استخراجها من الرد وعرض كل منها على حدى، وفي الفقرة التالية سنضيف ميزة الدخول إلى مواضيع فرعية من أي موضوع مقترح نريد معرفة المزيد عنه.
</p>

<h2>
	عرض مواضيع فرعية عن موضوع
</h2>

<p>
	يمكننا أن نطلب من ChatGPT توليد مواضيع فرعية من موضوع محدد اختاره المستخدم، مع طلب إرفاق شرح بسيط عن كل موضوع فرعي، لذا يجب إرسال تعليمة مختلفة عن السابقة نطلب بها توليد المواضيع الفرعية ونحدد شكل الخرج الذي نريده ليسهل علينا استخراجه من الطلب، والصيغة التي سنرسلها ستكون كالتالي:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		اقترح بعض الأفكار الفرعية عن &lt;اسم الموضوع&gt; لأتعلم عنها مع شرح قصير عن كل منها بالصيغة التالية:
	</p>

	<p>
		الفكرة شرح قصير
	</p>

	<p>
		الفكرة شرح قصير
	</p>

	<p>
		الأفكار الفرعية بالصيغة السابقة:
	</p>
</blockquote>

<p>
	حيث نستبدل <code>&lt;اسم الموضوع&gt;</code> بعنوان الموضوع الذي اختاره المستخدم، ونلاحظ كيف أرفقنا أمثلة عن شكل الخرج المطلوب وفي نهاية التعليمة نرشد النموذج أن يبدأ مباشرة بتوليد تلك الأفكار بالصيغة المُحددة، ولإرسال تلك التعليمة وتحويل الرد المولّد عنها إلى كائنات بعنوان ضمن الحقل <code>title</code> وشرح عنها ضمن الحقل <code>desc</code> نُعرّف التابع <code>getSubSubjects</code> والذي يقبل كمعامل أول عنوان الموضوع ويستدعي داخله التابع <code>chatGPT</code> ويمرر التعليمة مدرجًا ضمنها الموضوع المٌمرر، ثم يحول الرد إلى كائنات مواضيع بالصيغة المطلوبة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1960_22" style=""><span class="kwd">function</span><span class="pln"> getSubSubjects</span><span class="pun">(</span><span class="pln">subject</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// توليد التعليمة</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> prompt </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`اقترح</span><span class="pln"> </span><span class="pun">بعض</span><span class="pln"> </span><span class="pun">الأفكار</span><span class="pln"> </span><span class="pun">الفرعية</span><span class="pln"> </span><span class="pun">عن</span><span class="pln"> </span><span class="str">"${subject}"</span><span class="pln"> </span><span class="pun">لأتعلم</span><span class="pln"> </span><span class="pun">عنها</span><span class="pln"> </span><span class="pun">مع</span><span class="pln"> </span><span class="pun">شرح</span><span class="pln"> </span><span class="pun">قصير</span><span class="pln"> </span><span class="pun">عن</span><span class="pln"> </span><span class="pun">كل</span><span class="pln"> </span><span class="pun">منها</span><span class="pln"> </span><span class="pun">بالصيغة</span><span class="pln"> </span><span class="pun">التالية:</span><span class="pln">

</span><span class="pun">الفكرة</span><span class="pln">
</span><span class="pun">شرح</span><span class="pln"> </span><span class="pun">قصير</span><span class="pln">

</span><span class="pun">الفكرة</span><span class="pln">
</span><span class="pun">شرح</span><span class="pln"> </span><span class="pun">قصير</span><span class="pln">

</span><span class="pun">الأفكار</span><span class="pln"> </span><span class="pun">الفرعية</span><span class="pln"> </span><span class="pun">بالصيغة</span><span class="pln"> </span><span class="pun">السابقة:`</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> chatGPT</span><span class="pun">(</span><span class="pln">prompt</span><span class="pun">)</span><span class="pln">
        </span><span class="com">// تحويل الرد إلى كائنات</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">subjects </span><span class="pun">=&gt;</span><span class="pln"> subjects</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">'\n\n'</span><span class="pun">).</span><span class="pln">map</span><span class="pun">(</span><span class="pln">subject </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">title</span><span class="pun">,</span><span class="pln"> desc</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> subject</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">'\n'</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> title</span><span class="pun">,</span><span class="pln"> desc </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}))</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نريد توليد مواضيع فرعية عند ضغط المستخدم على موضوع ما، لذا نُعدل التابع <code>renderSubjects</code> لإضافة تابع معالجة لحدث الضغط <code>click</code> والذي سيستدعي تابع توليد المواضيع الفرعية <code>getSubSubjects</code> مع تمرير عنوان الموضوع الذي اختاره المستخدم، ثم يمرر النتيجة للتابع نفسه <code>renderSubjects</code> كي تُعرض المواضيع الفرعية بدل الحالية، ونضيف لكل موضوع الشرح من الحقل <code>desc</code> في حال وجوده كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1960_24" style=""><span class="kwd">function</span><span class="pln"> renderSubjects</span><span class="pun">(</span><span class="pln">subjects</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> subject </span><span class="kwd">of</span><span class="pln"> subjects</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">const</span><span class="pln"> $subject </span><span class="pun">=</span><span class="pln"> $</span><span class="pun">(`&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"subject"</span><span class="pun">&gt;&lt;/</span><span class="pln">div</span><span class="pun">&gt;`)</span><span class="pln">

        </span><span class="com">// توليد المواضيع الفرعية عند الضغط</span><span class="pln">
        $subject</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">'click'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> getSubSubjects</span><span class="pun">(</span><span class="pln">subject</span><span class="pun">.</span><span class="pln">title</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">renderSubjects</span><span class="pun">))</span><span class="pln">

        $subject</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(`&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">$</span><span class="pun">{</span><span class="pln">subject</span><span class="pun">.</span><span class="pln">title</span><span class="pun">}&lt;/</span><span class="pln">h2</span><span class="pun">&gt;`)</span><span class="pln">

        </span><span class="com">// استخراج الشرح وعرضه</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">subject</span><span class="pun">.</span><span class="pln">desc</span><span class="pun">){</span><span class="pln">
            $subject</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(`&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">$</span><span class="pun">{</span><span class="pln">subject</span><span class="pun">.</span><span class="pln">desc</span><span class="pun">}&lt;/</span><span class="pln">p</span><span class="pun">&gt;`)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        $container</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">$subject</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	تجربة التطبيق
</h2>

<p>
	أصبح التطبيق جاهزًا بالكامل ويمكن للمستخدم الغوص إلى ما لا نهاية في المواضيع الفرعية عن الفرعية وهكذا، لنختبر ذلك باختيار موضوع العلوم الطبيعية والفيزيائية من القائمة السابقة ونرى النتيجة:
</p>

<p style="text-align: center;">
	<img alt="science.png" class="ipsImage ipsImage_thumbnailed" data-fileid="130571" data-unique="in2sws480" src="https://academy.hsoub.com/uploads/monthly_2023_07/science.thumb.png.7c244175af46fc31bb1fdca0f492dbae.png">
</p>

<p>
	ولد مواضيع فرعية مع شرح بسيط عن كل منها عن ذلك الموضوع لندخل مثلًا إلى موضوع الذكاء الاصطناعي:
</p>

<p style="text-align: center;">
	<img alt="ai.png" class="ipsImage ipsImage_thumbnailed" data-fileid="130567" data-unique="kmmkucj0p" src="https://academy.hsoub.com/uploads/monthly_2023_07/ai.thumb.png.d93a3e3e27af1e7f86d4d4f463bacf0e.png">
</p>

<p>
	أيضًا أصبحت المواضيع أكثر تخصصًا لنختر تعلم الآلة:
</p>

<p style="text-align: center;">
	<img alt="ml.png" class="ipsImage ipsImage_thumbnailed" data-fileid="130570" data-unique="g84lb7nb7" src="https://academy.hsoub.com/uploads/monthly_2023_07/ml.thumb.png.cd2370adf2d02b123c26699751034eb4.png">
</p>
<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة الذكاء الاصطناعي
		</p>

		<p class="banner-subtitle">
			احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة.
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/artificial-intelligence" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<a href="https://academy.hsoub.com/learn/artificial-intelligence" rel=""><img alt="دورة الذكاء الاصطناعي AI" src="https://academy.hsoub.com/learn/assets/images/courses/artificial-intelligence.png"></a>
	</div>
</div>
<h2>
	الختام
</h2>

<p>
	يمكن بتوكيل المستخدم بتوليد واستخدام مفاتيحه الخاصة بالسماح للمطور تطوير التطبيقات المعتمدة على الذكاء الاصطناعي وإتاحتها للاستخدام للجميع دون أي كلفة، والتطبيق الذي طورناه في هذا المقال يعتمد على المعرفة الكامنة ضمن نموذج ChatGPT لتوجيه توليد المحتوى الذي نرغب به، ويمكن التطوير على التطبيق بكثير من الأفكار فمثلًا إضافة رابط عودة للبداية، أو عرض المواضيع الفرعية تحت الموضوع التابعة له ليصبح التطبيق عبارة عن شجرة يمكن فردها إلى ما لا نهاية، أو إضافة زر لتوليد شرح أطول عن موضوع معين أو طلب سؤال محدد عن ذلك الموضوع، ونرى أن الأفكار لا حصر لها بسبب سهولة التعامل مع هذه النماذج باستخدام اللغة الطبيعية سواء ضمن التطبيق أو من دخل المستخدم.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="%5Bhttps://academy.hsoub.com/programming/php/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D8%B5%D9%81%D8%A9-%D9%84%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%AD-%D8%A7%D9%84%D9%88%D8%AC%D8%A8%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-chatgpt-%D9%88-dall-e-%D9%81%D9%8A-php-r2005/%5D(https://academy.hsoub.com/programming/php/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D8%B5%D9%81%D8%A9-%D9%84%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%AD-%D8%A7%D9%84%D9%88%D8%AC%D8%A8%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-chatgpt-%D9%88-dall-e-%D9%81%D9%8A-php-r2005/)" rel="">تطوير تطبيق 'وصفة' لاقتراح الوجبات باستخدام ChatGPT و DALL-E في PHP</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/nodejs/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D8%AE%D8%AA%D8%A8%D8%B1%D9%86%D9%8A-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-chatgpt-%D9%88%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D9%85%D8%B9-nodejs-r2018/" rel="">تطوير تطبيق 'اختبرني' باستخدام ChatGPT ولغة جافاسكربت مع Node.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/artificial-intelligence/%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B4%D8%B1%D9%8A-%D9%85%D9%82%D8%A7%D8%A8%D9%84-%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A-r1813/" rel="">الذكاء البشري مقابل الذكاء الاصطناعي</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2031</guid><pubDate>Mon, 24 Jul 2023 15:05:00 +0000</pubDate></item><item><title>&#x645;&#x639;&#x627;&#x644;&#x62C;&#x629; &#x627;&#x644;&#x645;&#x634;&#x627;&#x643;&#x644; &#x627;&#x644;&#x634;&#x627;&#x626;&#x639;&#x629; &#x644;&#x644;&#x62A;&#x648;&#x627;&#x641;&#x642; &#x645;&#x639; &#x627;&#x644;&#x645;&#x62A;&#x635;&#x641;&#x62D;&#x627;&#x62A; &#x641;&#x64A; &#x634;&#x64A;&#x641;&#x631;&#x629; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D9%85%D8%B4%D8%A7%D9%83%D9%84-%D8%A7%D9%84%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-%D9%84%D9%84%D8%AA%D9%88%D8%A7%D9%81%D9%82-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D9%81%D9%8A-%D8%B4%D9%8A%D9%81%D8%B1%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1972/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_05/---------.png.1ce547d7d75909673552b9665aa4695b.png" /></p>
<p>
	سنطّلع في هذا المقال على مشاكل التوافق مع المتصفحات Cross-browser الشائعة التي ستواجهها في شيفرة جافاسكربت JavaScript وكيفية إصلاحها، إذ يتضمن ذلك معلومات حول استخدام أدوات تطوير المتصفح لتعقّب المشاكل وإصلاحها، واستخدام تعويض نقص دعم المتصفحات Polyfill والمكتبات لحل المشاكل، والحصول على ميزات جافاسكربت الحديثة التي تعمل في المتصفحات القديمة وغير ذلك.
</p>

<ul>
	<li>
		<strong>المتطلبات الأساسية</strong>: يجب أن تتعلم أساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، وأن تكون لديك فكرة عن <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1-%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%84%D9%84%D8%AA%D9%88%D8%A7%D9%81%D9%82-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-r1953/" rel="">المبادئ عالية المستوى لاختبار التوافق مع المتصفحات</a>.
	</li>
	<li>
		<strong>الهدف</strong>: أن تكون قادرًا على تشخيص مشاكل شيفرة جافاسكربت الشائعة على المتصفحات المختلفة واستخدام الأدوات والأساليب المناسبة لإصلاحها.
	</li>
</ul>

<h2>
	مشاكل شيفرة جافاسكربت
</h2>

<p>
	عانت <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-javascript-r664/" rel="">لغة جافاسكربت</a> في السابق من مشاكل التوافق مع المتصفحات المختلفة، إذ طُبِّقت سكربتات خيارات المتصفح الرئيسية في التسعينات (متصفح Internet Explorer وNetscape) باستخدام لغات مختلفة، فقد طُبِّق Netscape باستخدام لغة جافاسكربت، واحتوى المتصفح IE على لغة JScript مع وجود لغة VBScript على أساس خيارآخر، كما تُعَدّ كل من لغتَي جافاسكربت و JScript متوافقتين إلى حد ما، إذ يعتمد كلاهما على مواصفات لغة ECMAScript، ولكن طُبِّقت الأشياء بطرق متضاربة وغير متوافقة في أغلب الأحيان، مما تسبب في العديد من المشاكل للمطورين.
</p>

<p>
	استمرت مشاكل عدم التوافق في أوائل الألفينات، حيث كانت المتصفحات القديمة لا تزال قيد الاستخدام و بحاجة إلى الدعم، وهذا هو أحد الأسباب الرئيسية لظهور مكتبات مثل مكتبة <a href="https://wiki.hsoub.com/jQuery" rel="external">jQuery</a> لتجريد الاختلافات في تطبيقات المتصفح، بحيث يتعين على المطورين كتابة جزء بسيط من الشيفرة البرمجية فقط، وبالتالي ستعالج مكتبة jQuery -أو أي مكتبة أخرى تستخدِمها- بعد ذلك الاختلافات في الخلفية، لذلك لن تضطر إلى معالجة هذه الاختلافات.
</p>

<p>
	تحسنت الأمور بصورة ملحوظة منذ ذلك الحين، إذ تدعم المتصفحات الحديثة ميزات جافاسكربت القديمة، وقد تضاءلت متطلبات استخدام مثل هذه الشيفرة البرمجية نظرًا لتقليل متطلبات دعم المتصفحات القديمة بالرغم من مراعاة أنها لم تختفِ تمامًا، ويمكن ملاحظة معظم مشاكل جافاسكربت مع المتصفحات المختلفة حاليًا كما يلي:
</p>

<ul>
	<li>
		عندما تمنع شيفرة التعرف على المتصفح Browser Sniffing ذات الجودة الرديئة وشيفرة اكتشاف الميزات واستخدام بادئة المصنِّع المتصفحاتِ من تشغيل الشيفرة البرمجية التي يمكن استخدامها بطريقة جيدة.
	</li>
	<li>
		عندما يستخدِم المطورون ميزات جافاسكربت الجديدة وواجهات برمجة تطبيقات الويب الحديثة في شيفرتهم البرمجية ثم يكتشفون أنّ هذه الميزات لا تعمل في المتصفحات القديمة.
	</li>
</ul>

<h2>
	إصلاح مشاكل شيفرة جافاسكربت العامة
</h2>

<p>
	يجب أن تتأكد من عمل شيفرتك البرمجية بنجاح قبل الاستمرار في التركيز على مشاكل التوافق مع المتصفحات، فإذا لم تعرف مسبقًا أساسيات استكشاف أخطاء شيفرة جافاسكربت وإصلاحها، فيجب الاطلاع على مقال <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B2%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1245/" rel="">الزلات البرمجية وأخطاء في جافاسكربت</a> قبل المضي قدمًا، وهناك عدد من مشاكل جافاسكربت الشائعة التي يجب أن تضعها في حساباتك مثل ما يلي:
</p>

<ul>
	<li>
		مشاكل الصياغة والمنطق الأساسية.
	</li>
	<li>
		التأكد من تعريف المتغيرات وغيرها ضمن النطاق الصحيح، وأنك لا تواجه تعارضًا بين العناصر المُصرَّح عنها في أماكن مختلفة.
	</li>
	<li>
		الارتباك عند استخدام <code>this</code> من حيث النطاق الذي يُطبَّق فيه، وبالتالي الارتباك حول ما إذا كانت قيمته هي ما قصدته، كما يمكنك الاطلاع على أمثلة مثل <a href="https://github.com/mdn/learning-area/blob/7ed039d17e820c93cafaff541aa65d874dde8323/javascript/oojs/assessment/main.js#L143" rel="external nofollow">هذا المثال</a> الذي يُظهر نمطًا نموذجيًا لحفظ نطاق <code>this</code> في متغير منفصل، ثم استخدام هذا المتغير في الدوال المتداخلة حتى تتمكن من التأكد من أنك تطبّق الدالة على نطاق <code>this</code> الصحيح.
	</li>
	<li>
		الاستخدام غير الصحيح للدوال ضمن الحلقات التي تتكرر باستخدام متغير عام أو استخدام نطاقه بطريقة خاطئة، إذ تُنفَّذ الحلقة عبر 10 تكرارات باستخدام متغير معرَّف باستخدام <code>var</code> في المثال <a href="https://mdn.github.io/learning-area/tools-testing/cross-browser-testing/javascript/bad-for-loop.html" rel="external nofollow">bad-for-loop.html</a> (اطّلع على <a href="https://github.com/mdn/learning-area/blob/main/tools-testing/cross-browser-testing/javascript/bad-for-loop.html" rel="external nofollow">شيفرته البرمجية</a>) في كل مرة ننشئ فيها فقرة ونضيف معالج الحدث <code>onclick</code> إليها، إذ نريد أن تعرض كل فقرة رسالة تنبيه تحتوي على رقمها (قيمة <code>i</code> عند إنشائه) عند النقر عليها، ولكن تعطي جميعها القيمة 11 للمتغير <code>i</code> لأن الحلقة <code>for</code> تنفّذ جميع تكراراتها قبل استدعاء الدوال المتداخلة.
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: الحل الأسهل هو التصريح عن متغير التكرار باستخدام <code>let</code> بدلًا من <code>var</code>، بحيث تكون قيمة <code>i</code> المرتبطة بالدالة فريدةً لكل تكرار، لكن لسوء الحظ لا تعمل هذه الطريقة بصورة صحيحة في المتصفح IE11، لذلك لم نستخدِمها في حلقة <code>for</code> الجيدة.
</p>

<p>
	إذا أردت نجاح هذه الطريقة، فيمكنك تعريف دالة منفصلة لإضافة معالج الحدث واستدعاؤها في كل تكرار وتمرير قيمتَي <code>para</code> و <code>i</code> الحاليتين إليها في كل مرة، ويمكنك الاطلاع على المثال <a href="https://mdn.github.io/learning-area/tools-testing/cross-browser-testing/javascript/good-for-loop.html" rel="external nofollow">good-for-loop.html</a> لمعرفة الإصدار الذي يعمل بنجاح، والاطلاع على <a href="https://github.com/mdn/learning-area/blob/main/tools-testing/cross-browser-testing/javascript/good-for-loop.html" rel="external nofollow">شيفرته البرمجية</a>.
</p>

<ul>
	<li>
		التأكد من إعادة العمليات غير المتزامنة قبل محاولة استخدام القيم التي تعيدها، إذ يتحقق <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX/Getting_Started#step_3_%e2%80%93_a_simple_example" rel="external nofollow">مثال Ajax</a> من اكتمال الطلب وإعادة الاستجابة قبل محاولة استخدامها لأي شيء آخر، وقد أصبح التعامل مع هذا النوع من العمليات أسهل من خلال استخدام <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%B9%D9%88%D8%AF-promise-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r915/" rel="">الوعود Promises</a> في لغة جافاسكربت.
	</li>
</ul>

<h3>
	منقحات الصياغة Linters
</h3>

<p>
	يمكنك ضمان جودة أفضل وشيفرة جافاسكربت أقل عرضة للأخطاء باستخدام منقّح الصياغة Linter كما هو الحال مع شيفرة HTML و CSS، حيث يؤشر هذا المنقّح إلى الأخطاء ويمكنه إعطاء التحذيرات حول الممارسات السيئة وغير ذلك، ويمكن تخصيصه ليكون أكثر أو أقل صرامةً في الإبلاغ عن الأخطاء أو التحذيرات، ومن منقّحات صياغة شيفرة JavaScript/ECMAScript التي نوصي بها <a href="https://jshint.com/" rel="external nofollow">JSHint</a> و <a href="https://eslint.org/" rel="external nofollow">ESLint</a> التي يمكن استخدامها بعدة طرق، وسنشرح بعضها بالتفصيل لاحقًا.
</p>

<h4>
	تنقيح الصياغة على الإنترنت
</h4>

<p>
	توفر صفحة JSHint الرئيسية رابطًا عبر الإنترنت يسمح لك بإدخال شيفرة جافاسكربت على اليسار ويوفِّر الخرج على اليمين بما في ذلك المقاييس والتحذيرات والأخطاء.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2023_05/01_jshint-online.png.bddcf7404d402b522d9b102613d738d0.png" data-fileid="124674" data-fileext="png" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="124674" data-unique="6xf60sv1g" alt="01_jshint-online.png" src="https://academy.hsoub.com/uploads/monthly_2023_05/01_jshint-online.png.bddcf7404d402b522d9b102613d738d0.png"> </a>
</p>

<h4>
	إضافات محرر الشيفرة البرمجية
</h4>

<p>
	لا يُعَدّ اضطرارك إلى نسخ شيفرتك ولصقها في صفحة ويب للتحقق من صحتها عدة مرات أمرًا ملائمًا، فما تريده حقًا هو منقّح صياغة يتناسب مع سير عملك بأقل قدر من المتاعب، إذ تحتوي العديد من محررات الشيفرات على إضافات لتنقيح الشيفرة البرمجية مثل المحرر Atom من GitHub الذي يتضمن الإضافة JSHint، ويمكن تثبيت الإضافة كما يلي:
</p>

<ol>
	<li>
		ثبّت Atom إذا لم يكن لديك إصدار حديث مثبَّت مسبقًا.
	</li>
	<li>
		انتقل إلى مربع حوار تفضيلات Atom من قائمة Atom ثم التفضيلات Preferences على نظام Mac أو من قائمة ملف File ثم التفضيلات Preferences في نظامَي التشغيل Windows و Linux، ثم اختر خيار التثبيت Install في القائمة اليسرى.
	</li>
	<li>
		اكتب "jslint" في حقل نص البحث عن الحزم Search Packages واضغط على الزر Enter/Return للبحث عن الحزم المتعلقة بتنقيح الصياغة.
	</li>
	<li>
		يجب عليك رؤية حزمة بالاسم lint في أعلى القائمة، وبالتالي ثبّتها باستخدام زر التثبيت Install، إذ تعتمد منقّحات الصياغة الأخرى عليها في العمل، ثم ثبّت الإضافة linter-jshint.
	</li>
	<li>
		حمّل ملف جافاسكربت بعد انتهاء تثبيت الحزم، حيث سترى أي مشاكل مميزة باللون الأخضر (للتحذيرات) مع وجود الدوائر الحمراء بجوار أرقام الأسطر (للأخطاء) ولوحة منفصلة في الأسفل توفر أرقام الأسطر ورسائل الخطأ والقيم المقترحة أو الإصلاحات الأخرى في بعض الأحيان.
	</li>
</ol>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2023_05/02_jshint-linter.png.0fdfc0768eb654650d65da0d9cfec93e.png" data-fileid="124673" data-fileext="png" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="124673" data-unique="ey39p4tii" alt="02_jshint-linter.png" src="https://academy.hsoub.com/uploads/monthly_2023_05/02_jshint-linter.png.0fdfc0768eb654650d65da0d9cfec93e.png"> </a>
</p>

<p>
	تتوفر حزم تنقيح مماثلة في المحررات المشهورة الأخرى، ويمكنك مراجعة قسم "إضافات محررات النصوص وبيئات التطوير IDE" في <a href="https://jshint.com/install/" rel="external nofollow">صفحة تثبيت JSHint</a>.
</p>

<h4>
	استخدامات أخرى
</h4>

<p>
	هناك طرق أخرى لاستخدام هذه المنقّحات، حيث يمكنك الاطلاع على صفحات تثبيت <a href="https://jshint.com/install/" rel="external nofollow">JSHint</a> و <a href="https://eslint.org/docs/user-guide/getting-started" rel="external nofollow">ESLint</a>، كما يمكنك تثبيتها باستخدام واجهة سطر الأوامر Command Line Interface -أو CLI اختصارًا- عبر مدير الحزم Node Package Manager -أو اختصارًا npm، ولكن يجب تثبيت NodeJS أولًا.
</p>

<p>
	يثبّت الأمر التالي المنقّح JSHint:
</p>

<pre class="ipsCode">npm install -g jshint
</pre>

<p>
	يمكنك بعد ذلك الإشارة إلى هذه الأدوات في ملفات جافاسكربت التي تريد تنقيحها كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2023_05/03_js-hint-commandline.png.39ac25e060f9e52a8ebbdb29c7a620d1.png" data-fileid="124672" data-fileext="png" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="124672" data-unique="pv160mwil" alt="03_js-hint-commandline.png" src="https://academy.hsoub.com/uploads/monthly_2023_05/03_js-hint-commandline.png.39ac25e060f9e52a8ebbdb29c7a620d1.png"> </a>
</p>

<p>
	يمكنك استخدام هذه الأدوات مع أداة تشغيل/بناء المهام مثل <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D8%AF%D8%A7%D8%A9-%D8%A7%D9%84%D8%A8%D9%86%D8%A7%D8%A1-gulp-r663/" rel="">Gulp</a> أو <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-webpack-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-r866/" rel="">Webpack</a> لتنقيح أخطاء شيفرة جافاسكربت تلقائيًا أثناء التطوير، إذ تدعم الأداة <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D8%AF%D8%A7%D8%A9-%D8%A7%D9%84%D8%A8%D9%86%D8%A7%D8%A1-gulp-r663/" rel="">Grunt</a> المنقّح JSHint الذي تدعمه أدوات أخرى مثل <a href="https://github.com/webpack-contrib/jshint-loader" rel="external nofollow">محمِّل JSHint الخاص بالأداة Webpack</a>.
</p>

<p>
	<strong>ملاحظة</strong>: يحتاج المنقّح ESLint إعدادًا وضبطًا أكبر قليلًا من المنقّح JSHint، ولكنه أقوى.
</p>

<h3>
	أدوات المطور في المتصفحات
</h3>

<p>
	تحتوي <a href="https://academy.hsoub.com/programming/workflow/%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D9%85%D8%B7%D9%88%D8%B1%D9%8A-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D8%AF%D9%85%D8%AC%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-r1439/" rel="">أدوات المطور</a> في المتصفحات على العديد من الميزات المفيدة للمساعدة في تصحيح أخطاء شيفرة جافاسكربت، حيث ستعطي أولًا طرفية جافاسكربت تقريرًا بأخطاء شيفرتك البرمجية.
</p>

<p>
	أنشئ نسخةً محليةً من المثال <a href="https://mdn.github.io/learning-area/tools-testing/cross-browser-testing/javascript/broken-ajax.html" rel="external nofollow">broken-ajax.html</a> واطلع على <a href="https://github.com/mdn/learning-area/blob/main/tools-testing/cross-browser-testing/javascript/broken-ajax.html" rel="external nofollow">شيفرته البرمجية</a>، إذ سترى في الطرفية رسالة الخطأ "Uncaught TypeError: can't access property "length", heroes is undefined"، ورقم السطر المشار إليه هو 49، والذي يمثِّل قسم الشيفرة التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_6" style=""><span class="kwd">function</span><span class="pln"> showHeroes</span><span class="pun">(</span><span class="pln">jsonObj</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> heroes </span><span class="pun">=</span><span class="pln"> jsonObj</span><span class="pun">[</span><span class="str">'members'</span><span class="pun">];</span><span class="pln">

  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> hero </span><span class="kwd">of</span><span class="pln"> heroes</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// …</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// …</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لذا ستفشل الشيفرة البرمجية بمجرد محاولة الوصول إلى خاصية <code>jsonObj</code> التي يُفترَض أن تكون <a href="https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-json-%D9%81%D9%8A-javascript-r548/" rel="">كائن JSON</a>، وتُجلَب من ملف <code>‎.json</code> خارجي باستخدام استدعاء <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86-xmlhttprequest-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1299/" rel="">XMLHttpRequest</a> التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_8" style=""><span class="kwd">let</span><span class="pln"> requestURL </span><span class="pun">=</span><span class="pln"> </span><span class="str">'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">XMLHttpRequest</span><span class="pun">();</span><span class="pln">
request</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="str">'GET'</span><span class="pun">,</span><span class="pln"> requestURL</span><span class="pun">);</span><span class="pln">
request</span><span class="pun">.</span><span class="pln">send</span><span class="pun">();</span><span class="pln">

</span><span class="kwd">let</span><span class="pln"> superHeroes </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">response</span><span class="pun">;</span><span class="pln">
populateHeader</span><span class="pun">(</span><span class="pln">superHeroes</span><span class="pun">);</span><span class="pln">
showHeroes</span><span class="pun">(</span><span class="pln">superHeroes</span><span class="pun">);</span></pre>

<p>
	ولكن سيفشل هذا الاستدعاء.
</p>

<h4>
	واجهة برمجة تطبيقات الطرفية Console <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>
</h4>

<p>
	يُحتمَل أننا نعرف ما هو الخطأ في هذه الشيفرة، ولكن لنتعرّف أكثر على كيفية تحرّي هذا الأمر، فهناك واجهة برمجة تطبيقات طرفية تسمح لشيفرة جافاسكربت البرمجية بالتفاعل مع طرفية جافاسكربت الخاصة بالمتصفح التي تحتوي على عدد من الميزات المتاحة، ولكن الميزة الرئيسية التي ستستخدِمها في أغلب الأحيان هي <code>console.log()‎</code> والتي تطبع رسالةً مخصصةً في الطرفية.
</p>

<p>
	حاول إدخال السطر التالي بعد السطر رقم 31 مباشرةً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_10" style=""><span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Response value: '</span><span class="pun">,</span><span class="pln"> superHeroes</span><span class="pun">);</span></pre>

<p>
	حدّث الصفحة في المتصفح وستحصل على الخرج "Response value:‎" في الطرفية، بالإضافة إلى رسالة الخطأ نفسها التي رأيناها سابقًا.
</p>

<p>
	يُظهِر خرج التابع <code>console.log()‎</code> أنّ الكائن <code>superHeroes</code> لا يبدو أنه يحتوي على أيّ شيء، وهناك مشكلة شائعة جدًا في الطلبات غير المتزامنة عندما تحاول تطبيق شيء ما مع الكائن <code>response</code> قبل إعادته من الشبكة، إذًا لنصلح هذه المشكلة من خلال تشغيل الشيفرة البرمجية بمجرد إطلاق الحدث <code>load</code>، لذا أزل سطر <code>console.log()‎</code> وعدّل كتلة الشيفرة البرمجية التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_12" style=""><span class="kwd">let</span><span class="pln"> superHeroes </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">response</span><span class="pun">;</span><span class="pln">
populateHeader</span><span class="pun">(</span><span class="pln">superHeroes</span><span class="pun">);</span><span class="pln">
showHeroes</span><span class="pun">(</span><span class="pln">superHeroes</span><span class="pun">);</span></pre>

<p>
	إلى ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_14" style=""><span class="pln">request</span><span class="pun">.</span><span class="pln">onload </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> superHeroes </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">response</span><span class="pun">;</span><span class="pln">
  populateHeader</span><span class="pun">(</span><span class="pln">superHeroes</span><span class="pun">);</span><span class="pln">
  showHeroes</span><span class="pun">(</span><span class="pln">superHeroes</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا لم يعمل شيء ما في أيّ وقت ولم تكن القيمة كما يجب أن تكون في الشيفرة البرمجية، فيمكنك استخدام التابع <code>console.log()‎</code> لطباعتها ومعرفة ما يحدث.
</p>

<h4>
	استخدام مصحح أخطاء جافاسكربت
</h4>

<p>
	لا يزال الخطأ نفسه موجودًا ولم تختفِ المشكلة لسوء الحظ، فلنتحقق من ذلك باستخدام ميزة أكثر تعقيدًا لأدوات مطور المتصفح وهي <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%86%D9%82%D9%8A%D8%AD-%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%B4%D9%8A%D9%81%D8%B1%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D9%81%D9%8A-chrome-r784/" rel="">مصحح أخطاء جافاسكربت</a> JavaScript debugger كما يطلق عليه في Firefox.
</p>

<p>
	<strong>ملاحظة</strong>: تتوفر أدوات مماثلة في متصفحات أخرى مثل <a href="https://developer.chrome.com/docs/devtools/#sources" rel="external nofollow">تبويب المصادر Sources</a> في Chrome و Debugger في Safari (اطلّع على <a href="https://developer.apple.com/safari/tools/" rel="external nofollow">أدوات تطوير الويب في Safari</a>) وغيرها.
</p>

<p>
	يبدو تبويب Debugger في Firefox كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2023_05/04_debugger-tab.png.446b50730997438ae2deebf831c0cfd8.png" data-fileid="124671" data-fileext="png" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="124671" data-unique="6ybf48g11" alt="04_debugger-tab.png" src="https://academy.hsoub.com/uploads/monthly_2023_05/04_debugger-tab.png.446b50730997438ae2deebf831c0cfd8.png"> </a>
</p>

<ul>
	<li>
		يمكنك تحديد السكربت الذي تريد تصحيحه على اليسار (لدينا سكربت واحد فقط في حالتنا).
	</li>
	<li>
		تعرض اللوحة المركزية الشيفرة في السكربت المحدَّد.
	</li>
	<li>
		تعرض اللوحة اليمنى تفاصيل مفيدة تتعلق بالبيئة الحالية مثل نقاط الإيقاف Breakpoints ومكدس الاستدعاءات Callstack والنطاقات Scopes النشطة حاليًا.
	</li>
</ul>

<p>
	الميزة الرئيسية لهذه الأدوات هي القدرة على إضافة نقاط توقف إلى الشيفرة البرمجية، وهي النقاط التي يتوقف فيها تنفيذ الشيفرة، ويمكنك فحص البيئة في حالتها الحالية ومعرفة ما يجري عند هذه النقطة.
</p>

<p>
	يُعطَى خطأ في السطر رقم 51، لذا انقر على هذا السطر في اللوحة المركزية لإضافة نقطة توقف إليه، حيث سترى سهمًا أزرق يظهر عليه، ثم حدّث الصفحة باستخدام الاختصار "Cmd/Ctrl + R"، حيث سيتوقف المتصفح مؤقتًا عن تنفيذ الشيفرة في السطر رقم 51، وستُحدَّث اللوحة اليمنى لإظهار بعض المعلومات المفيدة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2023_05/05_breakpoint.png.9aff2e898105226dbcd91672e2702869.png" data-fileid="124670" data-fileext="png" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="124670" data-unique="xxel8py6c" alt="05_breakpoint.png" src="https://academy.hsoub.com/uploads/monthly_2023_05/05_breakpoint.png.9aff2e898105226dbcd91672e2702869.png"> </a>
</p>

<ul>
	<li>
		سترى تفاصيل نقطة التوقف التي ضبطتها ضمن نقاط التوقف Breakpoints.
	</li>
	<li>
		سترى بعض المدخلات ضمن مكدس الاستدعاءات Call Stack الذي هو قائمة بسلسلة الدوال المستدعاة التي تؤدي إلى استدعاء الدالة الحالية، فلدينا في الأعلى الدالة <code>showHeroes()‎</code> التي نستخدمها حاليًا، ثم لدينا الدالة <code>onload</code> التي تخزن دالة معالج الأحداث التي تحتوي على استدعاء الدالة <code>showHeroes()‎</code>.
	</li>
	<li>
		سترى ضمن النطاقات Scopes النطاق النشط حاليًا للدالة التي نبحث عنها. لدينا حاليًا ثلاثة نطاقات فقط هي <code>showHeroes</code> و<code>block</code> و<code>Window</code> (النطاق العام)، كما يمكن توسيع كل نطاق لإظهار قيم المتغيرات ضمن النطاق عند توقف تنفيذ الشيفرة البرمجية.
	</li>
</ul>

<p>
	يمكننا العثور على بعض المعلومات المفيدة مثل:
</p>

<ol>
	<li>
		يمكنك أن ترى عند توسيع نطاق <code>showHeroes</code> أنّ المتغير <code>heroes</code> غير معرَّف <code>undefined</code>، مما يشير إلى أن الوصول إلى الخاصية <code>members</code> في الكائن <code>jsonObj</code> (السطر الأول من الدالة) لم ينجح.
	</li>
	<li>
		يمكنك أن ترى أنّ المتغير <code>jsonObj</code> يخزن سلسلةً نصيةً وليس كائن JSON.
	</li>
	<li>
		انقر على نطاق <code>onload</code> في قسم مكدس الاستدعاءات Call Stack، مما يؤدي إلى تحديث العرض لإظهار الدالة <code>request.onload</code> في اللوحة المركزية ونطاقاتها في قسم النطاقات Scopes.
	</li>
	<li>
		إذا وسّعت نطاق <code>onload</code>، فسترى أنّ المتغير <code>superHeroes</code> هو سلسلة نصية أيضًا وليس كائنًا، إذ يعيد استدعاء <code>XMLHttpRequest</code> سلسلة JSON نصية وليس كائن JSON.
	</li>
</ol>

<p>
	حاول حل هذه المشكلة بنفسك، إذ يمكنك إما إخبار كائن XMLHttpRequest صراحةً بإعادة تنسيق JSON أو تحويل النص المُعاد إلى JSON بعد وصول الاستجابة، فإذا واجهتك مشكلة، فيمكنك الرجوع إلى المثال <a href="https://github.com/mdn/learning-area/blob/main/tools-testing/cross-browser-testing/javascript/fixed-ajax.html" rel="external nofollow">fixed-ajax.html</a>.
</p>

<p>
	<strong>ملاحظة</strong>: يحتوي التبويب debugger على العديد من الميزات المفيدة الأخرى التي لم نناقشها هنا مثل نقاط التوقف الشرطية وتعابير المراقبة.
</p>

<h3>
	مشاكل الأداء
</h3>

<p>
	بما أن تطبيقاتك تصبح أكثر تعقيدًا وتستخدم مزيدًا من شيفرة جافاسكربت، فيمكن أن تبدأ في مواجهة مشاكل في الأداء خاصة عند عرض التطبيقات على أجهزة أبطأ، ويُعَدّ الأداء موضوعًا ضخمًا، لذلك لن نغطيه في هذا المقال بالتفصيل، ولكن إليك بعض النصائح السريعة:
</p>

<ul>
	<li>
		يمكنك تجنب تحميل المزيد من شيفرة جافاسكربت أكثر مما تحتاج إليه من خلال تجميع سكربتاتك في ملف واحد باستخدام حل ما مثل <a href="https://browserify.org/" rel="external nofollow">Browserify</a>، كما يُعَدّ تقليل عدد طلبات HTTP مفيدًا جدًا للأداء.
	</li>
	<li>
		صغّر ملفاتك قبل تحميلها على خادم الإنتاج، إذ يؤدي التصغير إلى ضغط الشيفرة البرمجية بأكملها في سطر واحد ضخم، مما يجعلها تشغل حجم ملف أقل بكثير، فيمكن أن تبدو الشيفرة غير مقروءة بعد التصغير، ولكن لا داعي لقراءتها عند الانتهاء منها، كما يُفضَّل تطبيق التصغير باستخدام أداة تصغير مثل <a href="https://github.com/mishoo/UglifyJS" rel="external nofollow">Uglify</a>، وهناك أدوات عبر الإنترنت مثل <a href="https://jscompress.com/" rel="external nofollow">JSCompress.com</a>.
	</li>
	<li>
		تأكّد عند استخدام <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api%D8%9F-r1512/" rel="">واجهات برمجة التطبيقات <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a> من إيقاف تشغيل ميزات واجهة برمجة التطبيقات عند عدم استخدامها، إذ يمكن أن تكون بعض استدعاءات <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> مكلفةً وتؤثر على قوة المعالجة، فعند عرض بث فيديو مثلًا، تأكّد من إيقاف تشغيله عند عدم رؤيته، وتأكّد عند تتبّع موقع الجهاز باستخدام استدعاءات تحديد الموقع الجغرافي المتكررة من إيقاف تشغيله عندما يتوقف المستخدم عن استخدامه.
	</li>
	<li>
		يمكن أن تؤثر التحريكات animations على الأداء كثيرًا لأنه مكلف حقًا، إذ توفِّر الكثير من مكتبات جافاسكربت إمكانات خاصةً بالتحريك ومبرمَجةً باستخدام لغة جافاسكربت، ولكن يُعَدّ إجراء التحريك باستخدام ميزات المتصفح الأصيلة Native مثل <a href="https://academy.hsoub.com/files/14-%D8%A7%D9%84%D8%AA%D8%AD%D8%B1%D9%8A%D9%83-%D8%B9%D8%A8%D8%B1-css/" rel="">CSS Animations</a> أو واجهة برمجة تطبيقات Web Animations أكثر فعاليةً من حيث التكلفة.
	</li>
</ul>

<h2>
	مشاكل شيفرة جافاسكربت للتوافق مع المتصفحات
</h2>

<p>
	سنلقي نظرةً في هذا القسم على بعض مشاكل شيفرة جافاسكربت الأكثر شيوعًا للتوافق مع المتصفحات، حيث سنقسمه إلى ما يلي:
</p>

<ul>
	<li>
		استخدام ميزات لغة جافاسكربت الأساسية الحديثة.
	</li>
	<li>
		استخدام ميزات واجهة برمجة تطبيقات الويب Web <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> الحديثة.
	</li>
	<li>
		استخدام شيفرة التعرف على المتصفح السيئة.
	</li>
	<li>
		مشاكل الأداء.
	</li>
</ul>

<h3>
	استخدام ميزات JavaScript/<abbr title="Application Programming Interface | واجهة برمجية">API</abbr> الحديثة
</h3>

<p>
	شرحنا في <a href="https://academy.hsoub.com/programming/html/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D9%85%D8%B4%D8%A7%D9%83%D9%84-%D8%A7%D9%84%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-%D9%84%D9%84%D8%AA%D9%88%D8%A7%D9%81%D9%82-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D9%81%D9%8A-%D8%B4%D9%8A%D9%81%D8%B1%D8%A9-html-%D9%88-css-r1955/" rel="">المقال السابق</a> بعض الطرق التي يمكن من خلالها معالجة أخطاء HTML و CSS والميزات غير المعروفة بسبب طبيعة هذه اللغات، ولغة جافاسكربت ليست متساهلةً مثل لغتَي HTML وCSS، ولكن إذا واجه محرك جافاسكربت أخطاءً أو صياغةً غير معروفة، فسيؤدي ذلك إلى ظهور أخطاء في كثير من الأحيان.
</p>

<p>
	هناك عدد من ميزات لغة جافاسكربت الحديثة المُعرَّفة في الإصدارات الحديثة من المواصفات والتي لن تعمل في المتصفحات القديمة، فبعضها هي عبارة عن صيغة أبسط أي طريقة أسهل وألطف لكتابة ما يمكنك فعله باستخدام الميزات الموجودة مسبقًا، وبعضها يقدِّم إمكانات جديدة مثل:
</p>

<ul>
	<li>
		تُعَدّ <a href="https://wiki.hsoub.com/JavaScript/Promise" rel="external">الوعود Promises</a> ميزةً جديدةً رائعةً لأداء العمليات غير المتزامنة وللتأكد من اكتمال هذه العمليات قبل استخدام الشيفرة التي تعتمد على نتائج هذه العمليات لشيء آخر، إذ تستخدِم واجهة Fetch <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> (المكافئ الحديث للكائن XMLHTTPRequest) على سبيل المثال وعودًا لجلب الموارد عبر الشبكة والتأكّد من إعادة الاستجابة قبل استخدامها مثل عرض صورة ضمن العنصر <code>&lt;img&gt;</code>، كما لم تُدعَم الوعود في المتصفح IE على الإطلاق ولكنها مدعومة على جميع المتصفحات الحديثة.
	</li>
	<li>
		توفِّر <a href="https://wiki.hsoub.com/JavaScript/Arrow_Functions" rel="external">الدوال السهمية Arrow Functions</a> صيغةً أقصر وأكثر ملاءمةً لكتابة دوال مجهولة الاسم، ويمكنك مراجعة المثال <a href="https://mdn.github.io/learning-area/tools-testing/cross-browser-testing/javascript/arrow-function.html" rel="external nofollow">arrow-function.html</a>، والاطلاع على <a href="https://github.com/mdn/learning-area/blob/main/tools-testing/cross-browser-testing/javascript/arrow-function.html" rel="external nofollow">شيفرته البرمجية</a>، كما تُدعَم الدوال السهمية على جميع المتصفحات الحديثة باستثناء المتصفح IE.
	</li>
	<li>
		يؤدي التصريح عن <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%B6%D8%B9-%D8%A7%D9%84%D8%B5%D8%A7%D8%B1%D9%85-%D8%A7%D9%84%D9%86%D9%85%D8%B7-%D8%A7%D9%84%D8%AD%D8%AF%D9%8A%D8%AB-%D9%84%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%B4%D9%8A%D9%81%D8%B1%D8%A7%D8%AA-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r670/" rel="">الوضع الصارم Strict Mode</a> في أعلى شيفرة جافاسكربت إلى تحليلها باستخدام مجموعة قواعد أكثر صرامةً، مما يعني ظهور مزيد من التحذيرات والأخطاء، وستُرفَض بعض الأشياء التي كانت مقبولةً سابقًا، ويُعَدّ استخدام الوضع الصارم فكرةً جيدةً لأنه ينشئ شيفرةً أفضل وأكثر كفاءةً، ولكن تدعمه المتصفحات دعمًا محدودًا أو غير مكتمل.
	</li>
	<li>
		تسمح مصفوفات النوع Typed Arrays لشيفرة جافاسكربت بالوصول إلى البيانات الثنائية الخام ومعالجتها، وهو أمر ضروري لأن واجهات برمجة تطبيقات المتصفح مثلًا تبدأ في معالجة تدفقات بيانات الفيديو والصوت الخام، إذ تتوفر هذه المصفوفات في الإصدار IE10 وما فوق وجميع المتصفحات الحديثة.
	</li>
</ul>

<p>
	هناك أيضًا العديد من واجهات برمجة التطبيقات الجديدة التي تظهر في المتصفحات الحديثة، والتي لا تعمل في المتصفحات القديمة مثل:
</p>

<ul>
	<li>
		واجهة IndexedDB <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> وواجهة Web Storage <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> وغيرها لتخزين بيانات موقع الويب على طرف العميل.
	</li>
	<li>
		واجهة Web Workers <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> لتشغيل شيفرة جافاسكربت في خيط Thread منفصل، مما يساعد على تحسين الأداء.
	</li>
	<li>
		واجهة WebGL <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> للرسومات ثلاثية الأبعاد الحقيقية.
	</li>
	<li>
		واجهة Web Audio <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> لمعالجة الصوت المتقدمة.
	</li>
	<li>
		واجهة WebRTC <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> لاتصال الفيديو/الصوت متعدد الأشخاص في الوقت الحقيقي مثل مؤتمرات الفيديو.
	</li>
	<li>
		واجهة WebVR <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> لهندسة تجارب الواقع الافتراضي في المتصفح مثل التحكم في عرض ثلاثي الأبعاد مع إدخال البيانات من أجهزة الواقع الافتراضي VR.
	</li>
</ul>

<p>
	هناك بعض الاستراتيجيات لمعالجة حالات عدم التوافق مع المتصفحات المتعلقة بدعم الميزات، فلنتعرف على أكثرها شيوعًا.
</p>

<p>
	<strong>ملاحظة</strong>: لا توجد هذه الاستراتيجيات بمعزل عن بعضها البعض، إذ يمكنك دمجها حسب الحاجة، فيمكنك مثلًا استخدام استراتيجية اكتشاف الميزات لتحديد ما إذا كانت الميزة مدعومةً؛ فإذا لم تكن كذلك، فيمكنك تشغيل الشيفرة البرمجية لتحميل تعويض نقص دعم المتصفحات Polyfill أو لتحميل مكتبة لمعالجة نقص الدعم.
</p>

<h4>
	اكتشاف دعم المتصفحات للميزات
</h4>

<p>
	تكمن الفكرة وراء اكتشاف الميزات في أنه يمكنك إجراء اختبار لتحديد ما إذا كانت ميزة جافاسكربت مدعومةً في المتصفح الحالي، ثم تشغيل الشيفرة البرمجية شرطيًا لتوفير تجربة مقبولة في كل من المتصفحات التي تدعم الميزة والمتصفحات التي لا تدعمها، إذ تملك واجهة Geolocation <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> مثلًا والتي تعرض بيانات الموقع المتاحة للجهاز الذي يعمل عليه متصفح الويب، نقطةَ دخول رئيسية لاستخدامها وهي الخاصية <code>geolocation</code> التي يوفرها الكائن العام <code>Navigator</code>، لذا يمكنك اكتشاف ما إذا كان المتصفح يدعم الخاصية <code>geolocation</code> أم لا باستخدام ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_16" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="str">"geolocation"</span><span class="pln"> in navigator</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  navigator</span><span class="pun">.</span><span class="pln">geolocation</span><span class="pun">.</span><span class="pln">getCurrentPosition</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">position</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// اعرض الموقع على الخريطة باستخدام‫ واجهة Google Maps API مثلًا</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// اجعل المستخدِم يختار من بين الخرائط الساكنة بدلًا من ذلك</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما يمكنك تطبيق مثل هذا الاختبار على ميزة CSS مثل اختبار وجود الخاصية <code>element.style</code> مثل <code>paragraph.style.transform !== undefined</code>، ولكن يُفضَّل بالنسبة لكل من CSS وجافاسكربت استخدام مكتبة لاكتشاف الميزات مُنشأَة مسبقًا بدلًا من كتابة مكتبتك الخاصة، وتُعَدّ مكتبة مودرنيزر Modernizr هي المعيار الصناعي لاختبارات اكتشاف الميزات.
</p>

<p>
	لا تخلط بين اكتشاف الميزات والتعرف على المتصفح Browser Sniffing (اكتشاف المتصفح المحدد الذي يصل إلى الموقع) الذي يُعَدّ ممارسةً سيئةً يجب عدم تطبيقها، ولاحظ أنه توجد بعض الميزات التي لا يمكن اكتشافها.
</p>

<p>
	<strong>ملاحظة</strong>: سنغطي اكتشاف الميزات بمزيد من التفصيل في مقال لاحق.
</p>

<h4>
	المكتبات
</h4>

<p>
	تُعَدّ مكتبات جافاسكربت وحدات شيفرة خارجية يمكنك ربطها بصفحتك، مما يوفر لك مجموعةً كبيرةً من الوظائف الجاهزة التي يمكن استخدامها مباشرةً، وبالتالي ستوفر الكثير من الوقت في هذه العملية، كما يمكن أن يكون سبب ظهور الكثير من مكتبات جافاسكربت أنّ مطورها قد أراد كتابة مجموعة من الدوال المساعدة لتوفير الوقت عند كتابة المشاريع المستقبلية ثم قرر إطلاقها لأن المطورين الآخرين قد وجدوها مفيدةً.
</p>

<p>
	تمتلك مكتبات جافاسكربت عدة أنواع رئيسية، ويمكن أن تخدم بعض المكتبات أكثر من غرض واحد من الأغراض التالية:
</p>

<ul>
	<li>
		المكتبات المساعدة Utility Libraries: توفِّر مجموعةً من الدوال التي تجعل المهام العادية وإدارتها أسهل، إذ توفر <a href="https://wiki.hsoub.com/jQuery" rel="external">مكتبة jQuery</a> مثلًا محدّدات كاملة الميزات ومكتبات معالجة نموذج DOM للسماح بتحديد نوع محدد CSS للعناصر في شيفرة جافاسكربت وتسهيل بناء نموذج DOM، كما ليس مهمًا الآن أن تكون لدينا ميزات حديثة مثل توابع <code>Document.querySelector()‎</code> أو <code>Document.querySelectorAll()‎</code> أو <code>Node</code> المتاحة على المتصفحات المختلفة، ولكن لا يزال ممكنًا أن تكون هذه الميزات مفيدةً عندما تحتاج المتصفحات القديمة إلى الدعم.
	</li>
	<li>
		مكتبات الملاءمة Convenience Libraries: تسهّل تطبيق الأشياء الصعبة، إذ تُعَدّ واجهة WebGL <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> معقدةً وصعبة الاستخدام عند كتابتها مباشرةً، لذا فإن مكتبة Three.js (وغيرها) مبنية على WebGL وتوفر واجهة برمجة تطبيقات أسهل كثيرًا لإنشاء كائنات وإضاءة وخامات ثلاثية الأبعاد، كما تُعَدّ واجهة Service Worker <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> معقدةً للغاية في الاستخدام، لذلك بدأت مكتبات الشيفرات في الظهور لتسهيل تطبيق حالات استخدامات واجهة Service Worker الشائعة.
	</li>
	<li>
		مكتبات التأثيرات Effects Libraries: صُمِّمت هذه المكتبات للسماح بإضافة تأثيرات خاصة بسهولة إلى مواقع الويب، وقد كانت هذه المكتبات أكثر فائدةً عندما كانت "DHTML" كلمةً شائعةً، حيث تضمَّن تطبيق تأثير ما الكثيرَ من شيفرة جافاسكربت المعقدة، ولكن المتصفحات حاليًا لديها الكثير من ميزات CSS وواجهات برمجة التطبيقات المبنية مسبقًا لتطبيق التأثيرات بسهولة أكبر.
	</li>
	<li>
		مكتبات واجهة المستخدِم UI Libraries: توفر توابعًا لتطبيق ميزات واجهة المستخدِم المعقدة التي يمكن أن يكون تطبيقها على المتصفحات المختلفة أمرًا صعبًا مثل Foundation و Bootstrap و Material-UI (تُعَدّ الأخيرة مجموعةً من المكونات للاستخدام مع إطار عمل React)، كما تُستخدَم هذه المكتبات بوصفها أساسًا لتخطيط الموقع بأكمل وليس لمجرد ميزة واجهة مستخدِم واحدة.
	</li>
	<li>
		مكتبات التوحيد Normalization Libraries: تمنحك صياغةً بسيطةً تسمح لك بإكمال مهمة بسهولة دون الحاجة إلى القلق بشأن الاختلافات بين المتصفحات، إذ ستعالِج هذه المكتبة واجهات برمجة التطبيقات المناسبة في الخلفية، لذا ستعمل الوظيفة مهما كان المتصف، كما تُعَدّ مكتبة LocalForage مثلًا مكتبة لتخزين البيانات من طرف العميل، حيث توفر صياغةً بسيطةً لتخزين البيانات واستردادها، وتستخدِم في الخلفية أفضل واجهة برمجة تطبيقات متاحة للمتصفح لتخزين البيانات سواءً كانت واجهة IndexedDB أو واجهة Web Storage أو حتى واجهة WebSQL (المهمَلة حاليًا، ولكنها لا تزال مدعومة في بعض الإصدارات القديمة من Safari و IE)، كما تُعَدّ مكتبة jQuery مثالًا آخر عن مكتبات التوحيد.
	</li>
</ul>

<p>
	تأكّد عند اختيار مكتبة لاستخدامها من أنها تعمل على مجموعة المتصفحات التي تريد دعمها واختبر تطبيقها بدقة وتأكّد من أن المكتبة منتشرة ومدعومة جيدًا ومن غير المحتمل أن تصبح قديمةً الأسبوع المقبل، وتحدَّث إلى المطورين الآخرين لمعرفة ما يوصون به واطلع على مقدار النشاط وعدد المساهمين في المكتبة على GitHub أو في أيّ مكان آخر مُخزَّنة فيه.
</p>

<p>
	تُستخدَم المكتبة من خلال تنزيل ملفات المكتبة (ملفات جافاسكربت وبعض ملفات CSS أو الاعتماديات الأخرى) وربطها بصفحتك -باستخدام العنصر <code>&lt;script&gt;</code> مثلًا- بالرغم من وجود العديد من خيارات الاستخدام الأخرى لمثل هذه المكتبات مثل تثبيتها بوصفها مكونات <a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%A7-%D9%87%D9%88-bower%D8%9F-r15/" rel="">Bower</a> أو تضمينها بوصفها اعتماديات باستخدام أداة تحزيم الوحدات <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-webpack-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-r866/" rel="">Webpack</a>، كما يجب عليك قراءة صفحات التثبيت الخاصة بهذه المكتبات لمزيد من المعلومات.
</p>

<p>
	<strong>ملاحظة</strong>: ستصادف أطر عمل جافاسكربت في عملك على الويب مثل إطار عمل <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-ember-r1648/" rel="">Ember</a> و<a href="https://academy.hsoub.com/programming/javascript/angular/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-angular-r1897/" rel="">Angular</a>، كما يمكن أن تكون المكتبات قابلة للاستخدام في حل المشاكل الفردية وإطلاقها في المواقع القائمة مسبقًا، ولكن تميل أطر العمل إلى أن تكون أكثر انسجامًا مع الحلول الكاملة لتطوير تطبيقات الويب المعقدة.
</p>

<h4>
	تعويض نقص دعم المتصفحات Polyfills
</h4>

<p>
	يتكون <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%88%D9%8A%D8%B6-%D9%86%D9%82%D8%B5-%D8%AF%D8%B9%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D9%84%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r795/" rel="">تعويض نقص دعم المتصفحات Polyfill</a> من ملفات جافاسكربت خارجية يمكنك وضعها في مشروعك، ولكنه يختلف عن المكتبات، إذ تحسّن المكتبات الوظائف الحالية وتسهّل الأمور، ولكن يوفر تعويض نقص دعم المتصفحات وظائفًا غير موجودة على الإطلاق.
</p>

<p>
	يستخدِم تعويض نقص دعم المتصفحات لغة جافاسكربت أو تقنيات أخرى لبناء دعم لميزة لا يدعمها المتصفح محليًا، حيث يمكنك تعويض نقص دعم المتصفحات مثل <a href="https://github.com/stefanpenner/es6-promise" rel="external nofollow">es6-promise</a> لإنشاء وعود تعمل في المتصفحات حيث تكون غير مدعومة بطريقة أصيلة، ولا تنسى أنه يجب عليك البحث عن تعويض دعم المتصفحات والتأكد من عمله وقابلية صيانته قبل استخدامه.
</p>

<p>
	سنستخدِم في المثال التالي Fetch Polyfill لتقديم الدعم لواجهة Fetch <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> في المتصفحات القديمة، وسنستخدِم es6-promise لأن واجهة Fetch تستخدِم الوعود كثيرًا، وبالتالي ستبقى المتصفحات التي لا تدعمها في مشكلة.
</p>

<ol>
	<li>
		أنشئ أولًا نسخةً محليةً من المثال <a href="https://github.com/mdn/learning-area/blob/main/tools-testing/cross-browser-testing/javascript/fetch-polyfill.html" rel="external nofollow">fetch-polyfill.html</a> ومن <a href="https://github.com/mdn/learning-area/blob/main/tools-testing/cross-browser-testing/javascript/flowers.jpg" rel="external nofollow">صورة الزهور</a> في مجلد جديد، إذ سنكتب شيفرةً لجلب صورة الزهور وعرضها في الصفحة.
	</li>
	<li>
		احفظ بعد ذلك نسخةً من شيفرة <a href="https://raw.githubusercontent.com/github/fetch/master/fetch.js" rel="external nofollow">Fetch Polyfill</a> في مجلد ملف HTML نفسه.
	</li>
	<li>
		طبّق سكربتات تعويض دعم المتصفحات Polyfill على الصفحة باستخدام الشيفرة التالية التي يجب أن تضعها قبل العنصر <code>&lt;script&gt;</code> الموجود مسبقًا بحيث تكون متاحةً على الصفحة عندما نبدأ باستخدام <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84%D8%A7%D8%AA-%D9%85%D8%AA%D9%82%D8%AF%D9%85%D8%A9-%D9%84%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-fetch-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1297/" rel="">واجهة Fetch</a>، كما أننا نحمّل تعويض دعم الوعود في المتصفحات Promise Polyfill من CDN بحيث يدعم المتصفح IE11 الوعود التي تتطلبها عملية الجلب:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9855_18" style=""><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.min.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"fetch.js"</span><span class="tag">&gt;&lt;/script&gt;</span></pre>

<ol start="4">
	<li>
		أضِف الشيفرة التالية ضمن العنصر <code>&lt;script&gt;</code> الأصلي:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_20" style=""><span class="kwd">const</span><span class="pln"> myImage </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.my-image'</span><span class="pun">);</span><span class="pln">

fetch</span><span class="pun">(</span><span class="str">'flowers.jpg'</span><span class="pun">).</span><span class="pln">then</span><span class="pun">((</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  response</span><span class="pun">.</span><span class="pln">blob</span><span class="pun">().</span><span class="pln">then</span><span class="pun">((</span><span class="pln">myBlob</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> objectURL </span><span class="pun">=</span><span class="pln"> URL</span><span class="pun">.</span><span class="pln">createObjectURL</span><span class="pun">(</span><span class="pln">myBlob</span><span class="pun">);</span><span class="pln">
    myImage</span><span class="pun">.</span><span class="pln">src </span><span class="pun">=</span><span class="pln"> objectURL</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">});</span></pre>

<ol start="5">
	<li>
		إذا حمّلت Fetch Polyfill الآن في متصفح لا يدعم Fetch مثل المتصفح IE، فيجب أن ترى صورة الزهور.
	</li>
</ol>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2023_05/06_fetch-image.jpg.5f4eca2dc1a2755e3ebcac52bfc3b390.jpg" data-fileid="124669" data-fileext="jpg" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="124669" data-unique="l667w8ga6" alt="06_fetch-image.jpg" src="https://academy.hsoub.com/uploads/monthly_2023_05/06_fetch-image.thumb.jpg.ed82cf340d2159bd75f9457fdf88bfe2.jpg"> </a>
</p>

<p>
	<strong>ملاحظة</strong>: يمكنك العثور على نسخة هذا المثال النهائية على <a href="https://mdn.github.io/learning-area/tools-testing/cross-browser-testing/javascript/fetch-polyfill-finished.html" rel="external nofollow">fetch-polyfill-finished.html</a> كما يمكنك الاطلاع على <a href="https://github.com/mdn/learning-area/blob/main/tools-testing/cross-browser-testing/javascript/fetch-polyfill-finished.html" rel="external nofollow">شيفرته البرمجية</a>.
</p>

<p>
	<strong>ملاحظة</strong>: هناك العديد من الطرق للاستفادة من تعويض نقص دعم المتصفحات Polyfill المختلفة، ولا تنسى الاطلاع على توثيق كل منها قبل استخدامها.
</p>

<p>
	لا بد أنك تتساءل عن سبب تحميل شيفرة تعويض نقص دعم المتصفحات إذا لم تكن بحاجتها، حسنًا، بما أنّ الموقع يصبح أكثر تعقيدًا وسيستخدِم مزيدًا من المكتبات وتعويضات نقص دعم المتصفحات Polyfills وغير ذلك، فلا بد أنك ستحمّل كثيرًا من الشيفرات البرمجية الإضافية، والتي يمكن أن تؤثر على الأداء خاصةً على الأجهزة ذات الإمكانات الأقل، لذا من المنطقي تحميل الملفات حسب الحاجة فقط، لكن يتطلب ذلك بعض الإعدادات الإضافية في شيفرة جافاسكربت، فأنت بحاجة إلى اختبار اكتشاف الميزات الذي يكتشف ما إذا كان المتصفح يدعم الميزة التي تحاول استخدامها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_22" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">browserSupportsAllFeatures</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  main</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  loadScript</span><span class="pun">(</span><span class="str">'polyfills.js'</span><span class="pun">,</span><span class="pln"> main</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> main</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ضع شيفرة التطبيق الفعلية هنا</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنشغّل أولًا شرطًا يتحقق مما إذا كانت الدالة <code>browserSupportsAllFeatures()‎</code> تعيد القيمة <code>true</code>، فإذا كان الأمر كذلك، فسنشغّل الدالة <code>main()‎</code> التي ستحتوي على جميع شيفرات تطبيقك، وتبدو الدالة <code>browserSupportsAllFeatures()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_24" style=""><span class="kwd">function</span><span class="pln"> browserSupportsAllFeatures</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> window</span><span class="pun">.</span><span class="typ">Promise</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">fetch</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	اختبرنا هنا ما إذا كان الكائن <code>Promise</code> والدالة <code>fetch()‎</code> موجودان في المتصفح، فإذا كان الشرطان محققين، فستعيد الدالة القيمة <code>true</code>. وإذا أعادت الدالة القيمة <code>false</code>، فسنشغّل الشيفرة في الجزء الثاني من الشرط، وهذا يؤدي إلى تشغيل دالة تسمى <code>loadScript()‎</code> التي تحمّل تعويض نقص دعم المتصفحات Polyfills في الصفحة، ثم تُشغَّل الدالة <code>main()‎</code> بعد انتهاء التحميل، إذ تبدو الدالة <code>loadScript()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_26" style=""><span class="kwd">function</span><span class="pln"> loadScript</span><span class="pun">(</span><span class="pln">src</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> js </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'script'</span><span class="pun">);</span><span class="pln">
  js</span><span class="pun">.</span><span class="pln">src </span><span class="pun">=</span><span class="pln"> src</span><span class="pun">;</span><span class="pln">
  js</span><span class="pun">.</span><span class="pln">onload </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    done</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
  js</span><span class="pun">.</span><span class="pln">onerror </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    done</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'Failed to load script '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> src</span><span class="pun">));</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">head</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">js</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تنشئ الدالة عنصر <code>&lt;script&gt;</code> جديد ثم تضبط سمته <code>src</code> على المسار الذي حددناه على أنه أول وسيط وهو <code>'polyfills.js'</code> عندما استدعينا الدالة <code>loadScript()‎</code> سابقًا، وسنشغّل الدالة التي حددناها على أنها الوسيط الثاني (<code>main()‎</code>) عند تحميل السكربت، فإذا حدث خطأ أثناء تحميل السكربت، فسنستدعي الدالة أيضًا، ولكن مع وجود خطأ مخصص يمكننا استرداده للمساعدة في تصحيح المشكلة في حال حدوثها.
</p>

<p>
	لاحظ أنّ الملف polyfills.js هو نوعان من تعويض نقص دعم المتصفحات Polyfills اللذين نستخدمهما معًا في ملف واحد، حيث طبّقنا ذلك يدويًا، ولكن هناك حلول أذكى تنشئ حزمًا تلقائيًا مثل أداة <a href="https://academy.hsoub.com/programming/workflow/%D8%A3%D9%8A%D9%87%D9%85%D8%A7-%D8%A3%D9%81%D8%B6%D9%84-%D9%83%D8%A3%D8%AF%D8%A7%D8%A9-%D9%85%D8%B3%D8%A7%D8%B9%D8%AF%D8%A9-webpack-%D8%A3%D9%85-browserify-%D9%85%D8%B9-gulp%D8%9F-r867/" rel="">Browserify</a>، ويُعَدّ تجميع ملفات JS في ملف واحد أمرًا جيدًا، مما يؤدي إلى تقليل عدد طلبات HTTP التي تحتاجها لتحسين أداء موقعك.
</p>

<p>
	يمكنك رؤية هذه الشيفرة قيد التنفيذ في المثال <a href="https://mdn.github.io/learning-area/tools-testing/cross-browser-testing/javascript/fetch-polyfill-only-when-needed.html" rel="external nofollow">fetch-polyfill-only-when-needed.html</a> والاطلاع على <a href="https://github.com/mdn/learning-area/blob/main/tools-testing/cross-browser-testing/javascript/fetch-polyfill-only-when-needed.html" rel="external nofollow">شيفرته البرمجية</a> التي كتبها فيليب والتون Philip Walton.
</p>

<p>
	<strong>ملاحظة</strong>: هناك بعض الخيارات الخارجية التي يجب مراعاتها مثل Polyfill.io، وهي مكتبة meta-polyfill التي ستنظر في إمكانات كل متصفح وتطبق تعويض Polyfill حسب الحاجة اعتمادًا على واجهات برمجة التطبيقات وميزات جافاسكربت التي تستخدِمها في شيفرتك البرمجية.
</p>

<h4>
	تحويل شيفرة جافاسكربت JavaScript transpiling
</h4>

<p>
	هناك خيار آخر أصبح شائعًا للأشخاص الذين يرغبون في استخدام ميزات جافاسكربت الحديثة، وهو تحويل الشيفرة البرمجية التي تستخدِم ميزات ECMAScript 6/ECMAScript 2015 إلى إصدار يعمل في المتصفحات القديمة.
</p>

<p>
	<strong>ملاحظة</strong>: تسمَّى هذه العملية بالتحويل transpiling لأنها لا تصرِّف compiling الشيفرة البرمجية إلى مستوى أدنى لتشغيلها على حاسوب كما تفعل مع شيفرة سي C، وإنما تغيِّر هذه الشيفرة إلى صياغة موجودة على المستوى نفسه من التجريد بحيث يمكن استخدامها بالطريقة نفسها ولكن في ظروف مختلفة قليلًا، وهي في حالتنا تحويل إحدى صيغ شيفرة جافاسكربت إلى صيغة أخرى.
</p>

<p>
	تحدثنا سابقًا عن <a href="https://academy.hsoub.com/programming/general/%D8%A7%D8%B3%D8%AA%D8%B1%D8%A7%D8%AA%D9%8A%D8%AC%D9%8A%D8%A7%D8%AA-%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%84%D9%84%D8%AA%D9%88%D8%A7%D9%81%D9%82-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-r1954/" rel="">الدوال السهمية</a> (اطلع على تنفيذ المثال <a href="https://mdn.github.io/learning-area/tools-testing/cross-browser-testing/javascript/arrow-function.html" rel="external nofollow">arrow-function.html</a> وعلى <a href="https://github.com/mdn/learning-area/blob/main/tools-testing/cross-browser-testing/javascript/arrow-function.html" rel="external nofollow">شيفرته البرمجية</a>)، حيث تعمل هذه الدوال في أحدث المتصفحات فقط.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_31" style=""><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">});</span></pre>

<p>
	يمكننا تحويل هذه الدالة إلى دالة تقليدية قديمة مجهولة الاسم بحيث ستعمل في المتصفحات القديمة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_33" style=""><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">/* … */</span><span class="pln"> </span><span class="pun">});</span></pre>

<p>
	الأداة الموصَى بها حاليًا لتحويل شيفرة جافاسكربت هي Babel التي توفر إمكانات التحويل لسمات اللغة المناسبة للتحويل، وتقدّم تعويض نقص دعم المتصفحات Polyfills لتوفير الدعم بالنسبة إلى الميزات التي لا يمكن تحويلها بسهولة إلى مكافئ أقدم، وأسهل طريقة لتجربة Babel هي استخدامها <a href="https://babeljs.io/repl/" rel="external nofollow">عبر الإنترنت</a>، مما يسمح لك بإدخال شيفرتك البرمجية على اليسار، وإخراج نسخة مُحوَّلة على اليمين.
</p>

<p>
	<strong>ملاحظة</strong>: هناك العديد من الطرق لاستخدام Babel مثل مشغّلات المهام وأدوات الأتمتة وغيرها.
</p>

<h3>
	استخدام شيفرة التعرف على المتصفح السيئة
</h3>

<p>
	تحتوي جميع المتصفحات على سلسلة وكيل المستخدِم User-agent النصية التي تحدد ما هو المتصفح (الإصدار والاسم ونظام التشغيل وأمور أخرى)، وقد اعتاد المطورون على استخدام ما يسمى بشيفرة التعرف على المتصفح Browser Sniffing سابقًا عندما استخدم الجميع تقريبًا متصفحات Netscape أو Internet Explorer لاكتشاف المتصفح الذي يستخدمه المستخدِم ومنحه الشيفرة المناسبة للعمل عليه، وقد بدت الشيفرة كما يلي بالرغم من أنه مثال مبسّط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_35" style=""><span class="kwd">let</span><span class="pln"> ua </span><span class="pun">=</span><span class="pln"> navigator</span><span class="pun">.</span><span class="pln">userAgent</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">ua</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="str">'Firefox'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// تشغيل الشيفرة البرمجية الخاصة بمتصفح‫ Firefox</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">ua</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="str">'Chrome'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// تشغيل الشيفرة البرمجية الخاصة بمتصفح‫ Chrome</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كانت الفكرة جيدةً إلى حد ما، إذ اكتشفت هذه الطريقة المتصفحَ الذي يعرض الموقع، وشغّلت الشيفرة البرمجية المناسبة للتأكد من أنّ المتصفح سيتمكن من استخدام موقعك بصورة جيدة.
</p>

<p>
	<strong>ملاحظة</strong>: جرب فتح طرفية جافاسكربت الآن وشغّل الخاصية <code>navigator.userAgent</code> لترى ما ستحصل عليه.
</p>

<p>
	لكن بدأ المطورون مع مرور الوقت برؤية مشاكل كبيرة في هذه الطريقة، إذ كانت الشيفرة عرضة للأخطاء، ولنفترض أنك تعلم أنّ إحدى الميزات لا تعمل في الإصدار Firefox 10 وما قبله مثلًا وطبّقتَ شيفرةً لاكتشاف ذلك، ثم ظهر الإصدار Firefox 11 الذي يُحتمَل ألّا يكون مدعومًا لأنه ليس الإصدار Firefox 10، لذا يجب عليك تغيير كل شيفرة التعرف على المتصفح بانتظام.
</p>

<p>
	طبّق العديد من المطورين شيفرة سيئة للتعرف على المتصفح ولم يجروا صيانةً عليها، ثم بدأت المتصفحات في منع استخدام مواقع الويب التي تحتوي على هذه الميزات التي طبّقوها منذ ذلك الحين، وقد أصبح ذلك شائعًا لدرجة أنّ المتصفحات بدأت في الكذب بشأن المتصفحات الموجودة في سلاسل وكيل المستخدِم User-agent النصية (أو ادعت بأن جميعها متصفحات) للتحايل على الشيفرات البرمجية، كما طبّقت المتصفحات تسهيلات للسماح للمستخدِمين بتغيير سلسلة وكيل المستخدِم التي أبلغ عنها المتصفح عند الاستعلام باستخدام شيفرة جافاسكربت، مما جعل المتصفح أكثر عرضةً للخطأ وبلا فائدة في النهاية.
</p>

<p>
	الدرس الذي يجب تعلّمه هنا هو أنه يجب ألّا تستخدِم أبدًا التعرف على المتصفح، فحالة الاستخدام الحقيقية الوحيدة لشيفرة التعرف على المتصفح حاليًا هي عند إصلاح خلل في إصدار محدد جدًا من متصفح معيّن، ولكن يمكن إصلاح معظم الأخطاء بسرعة كبيرة في دورات الإصدار السريع لبائعِي المتصفحات حاليًا، لذا فلن تستخدِم شيفرة التعرف على المتصفح إلا نادرًا، كما يُعَدّ اكتشاف الميزات دائمًا خيارًا أفضل، فإذا اكتشفت ما إذا كانت الميزة مدعومةً، فلن تحتاج لتغيير الشيفرة البرمجية عند ظهور إصدارات جديدة من المتصفح، وستكون الاختبارات أكثر وثوقيةً.
</p>

<p>
	إذا صادفت متصفحًا يستخدِم شيفرة التعرف على المتصفحات عند الانضمام إلى مشروع قائم، فابحث عما إذا كان يمكن استبداله بشيء أكثر منطقيةً، إذ يتسبب التعرف على المتصفح في حدوث كل أنواع الأخطاء مثل الخطأ 1308462.
</p>

<h3>
	التعامل مع بادئات جافاسكربت
</h3>

<p>
	تحدّثنا في <a href="https://academy.hsoub.com/programming/html/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D9%85%D8%B4%D8%A7%D9%83%D9%84-%D8%A7%D9%84%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-%D9%84%D9%84%D8%AA%D9%88%D8%A7%D9%81%D9%82-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D9%81%D9%8A-%D8%B4%D9%8A%D9%81%D8%B1%D8%A9-html-%D9%88-css-r1955/" rel="">المقال السابق</a> بالتفصيل حول التعامل مع بادئات CSS، كما تستخدِم تطبيقات جافاسكربت الجديدة البادئات Prefixes في بعض الأحيان بالرغم من أنّ لغة جافاسكربت تستخدِم الأحرف بحالة سنام الجمل بدلًا من الواصلة التي تستخدمها لغة CSS، فإذا اُستخدِمت بادئة مع كائن واجهة jshint <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> جديد بالاسم <code>Object</code>، فسيحدث ما يلي:
</p>

<ul>
	<li>
		سيستخدِم Mozilla البادئة <code>mozObject</code>.
	</li>
	<li>
		ستستخدِم Chrome/Opera/Safari البادئة <code>webkitObject</code>.
	</li>
	<li>
		سيستخدِم Microsoft البادئة <code>msObject</code>.
	</li>
</ul>

<p>
	إليك مثال مأخوذ من النسخة <a href="https://mdn.github.io/violent-theremin/" rel="external nofollow">violent-theremin</a> واطلع على <a href="https://github.com/mdn/violent-theremin" rel="external nofollow">شيفرته البرمجية</a>، حيث يستخدِم هذا المثال مزيجًا من واجهة Canvas <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> وواجهة Web Audio <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> لإنشاء أداة رسم ممتعة (وصاخبة):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_37" style=""><span class="kwd">const</span><span class="pln"> </span><span class="typ">AudioContext</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="typ">AudioContext</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">webkitAudioContext</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> audioCtx </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">AudioContext</span><span class="pun">();</span></pre>

<p>
	دُعِمت نقاط الدخول الرئيسية في حالة واجهة Web Audio <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> لاستخدام واجهة برمجة التطبيقات المدعومة في Chrome/Opera عبر الإصدارات ذات البادئة <code>webkit</code> (مع دعم الإصدارات التي بدون بادئة حاليًا)، فالطريقة السهلة للتغلب على هذا الموقف هي إنشاء إصدار جديد من الكائنات ذات البادئات في بعض المتصفحات، وجعلها مساوية للإصدار الذي بدون بادئة أو الإصدار ذي البادئة (أو أيّ إصدارات أخرى ذات بادئات يجب وضعها في الحسبان)، حيث سيُستخدَم الإصدار الذي يدعمه المتصفح الذي يعرض الموقع حاليًا، ويمكننا بعد ذلك استخدام هذا الكائن لمعالجة واجهة برمجة التطبيقات بدلًا من الكائن الأصلي، حيث ننشئ في هذه الحالة باني واجهة AudioContext معدلة، ثم ننشئ نسخةً جديدةً منها لاستخدامها في شيفرة Web Audio.
</p>

<p>
	يمكن تطبيق هذا النمط على أيّ ميزة جافاسكربت ذات بادئة، وتستفيد مكتبات وتعويض نقص دعم المتصفحات Polyfill في شيفرة جافاسكربت من هذا النوع من الشيفرة البرمجية لتجريد اختلافات المتصفحات للمطور قدر الإمكان.
</p>

<p>
	لم يكن من المفترض أبدًا استخدام الميزات ذات البادئات في مواقع الإنتاج، لأنها عرضة للتغيير أو الإزالة دون سابق إنذار وتتسبب في حدوث مشاكل في التوافق مع المتصفحات، فإذا أردت استخدام الميزات ذات البادئات، فتأكد من استخدام الميزات الصحيحة، كما يمكنك البحث عن المتصفحات التي تتطلب بادئات لميزات JavaScript/<abbr title="Application Programming Interface | واجهة برمجية">API</abbr> المختلفة على موسوعة حسوب أو MDN أو caniuse.com مثلًا، فإذا لم تكن متأكدًا، فيمكنك معرفة ذلك عن طريق إجراء بعض الاختبارات مباشرةً في المتصفحات.
</p>

<p>
	حاول مثلًا الدخول إلى طرفية مطور المتصفح واكتب ما يلي مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9855_39" style=""><span class="pln">window</span><span class="pun">.</span><span class="typ">AudioContext</span></pre>

<p>
	إذا كانت هذه الميزة مدعومةً في متصفحك، فستُستكمَل تلقائيًا.
</p>

<h2>
	العثور عن مساعدة
</h2>

<p>
	هناك العديد من المشاكل الأخرى التي ستواجهها في شيفرة جافاسكربت، ولكن أهم شيء يجب معرفته هو كيفية العثور على إجابات عبر الإنترنت، يمكنك إضافة أي سؤال برمجي يوجهك في <a href="https://academy.hsoub.com/questions/c3-programming/" rel="">قسم الأسئلة والأجوبة</a> في أكاديمية حسوب للحصول على إجابة من مبرمجين ذوي خبرة.
</p>

<h2>
	الخلاصة
</h2>

<p>
	يجب أن يمنحك هذا المقال المبادئ وبعض الأفكار حول كيفية معالجة المشاكل المتعلقة بشيفرة جافاسكربت التي يمكن أن تواجهها للتوافق مع المتصفحات.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript" rel="external nofollow">Handling common JavaScript problems</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/html/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D9%85%D8%B4%D8%A7%D9%83%D9%84-%D8%A7%D9%84%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-%D9%84%D9%84%D8%AA%D9%88%D8%A7%D9%81%D9%82-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D9%81%D9%8A-html-%D9%88-css-r1955/" rel="">معالجة المشاكل الشائعة للتوافق مع المتصفحات في HTML و CSS</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/html/%D8%A7%D9%83%D8%AA%D8%B4%D8%A7%D9%81-%D8%AF%D8%B9%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D9%84%D9%85%D9%8A%D8%B2%D8%A7%D8%AA-html5-r340/" rel="">اكتشاف دعم المتصفحات لميزات HTML5</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/apps/general/%D8%AA%D8%A3%D9%85%D9%8A%D9%86-%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%81%D9%8A-%D8%A7%D9%84%D8%B9%D8%A7%D9%84%D9%85-%D8%A7%D9%84%D8%B1%D9%82%D9%85%D9%8A-r382/" rel="">تأمين متصفحات الويب في العالم الرقمي</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1972</guid><pubDate>Sun, 07 May 2023 13:00:00 +0000</pubDate></item><item><title>&#x62F;&#x639;&#x645; &#x644;&#x63A;&#x629; TypeScript &#x641;&#x64A; &#x625;&#x637;&#x627;&#x631; &#x639;&#x645;&#x644; Svelte</title><link>https://academy.hsoub.com/programming/javascript/%D8%AF%D8%B9%D9%85-%D9%84%D8%BA%D8%A9-typescript-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1871/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/1175141752_TypeScript----Svelte-.png.9cb05060ffa915db8761a8ee35648d6b.png" /></p>
<p>
	تعرّفنا في <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AE%D8%A7%D8%B2%D9%86-stores-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1864/" rel="">المقال السابق على مخازن Svelte</a> وطبّقنا مخزننا المُخصَّص لاستمرار معلومات التطبيق على تخزين الويب، وألقينا نظرةً على استخدام موجّه الانتقال لتطبيق الحركة على <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">عناصر DOM</a> في إطار عمل Svelte.
</p>

<p>
	سنتعلم الآن كيفية استخدام لغة <a href="https://wiki.hsoub.com/TypeScript" rel="external">TypeScript</a> في تطبيقات Svelte، إذ سنتعلم أولًا ماهي لغة TypeScript وفوائدها وسنرى كيفية إعداد مشروعنا للعمل مع ملفات TypeScript، ثم سننتقل إلى تطبيقنا ونرى التعديلات التي يجب إجراؤها للاستفادة الكاملة من ميزات TypeScript.
</p>

<ul>
	<li>
		<strong>المتطلبات الأساسية</strong>: يوصَى على الأقل بأن تكون على دراية بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة باستخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471" rel="">سطر الأوامر أو الطرفية</a>، كما ستحتاج طرفية مثبَّت عليها node وnpm لتصريف وبناء تطبيقك.
	</li>
	<li>
		<strong>الهدف</strong>: تعلّم كيفية إعداد واستخدام لغة TypeScript عند تطوير تطبيقات Svelte.
	</li>
</ul>

<p>
	لاحظ أنّ تطبيقنا يعمل جيدًا، ويُعَدّ نقله إلى لغة TypeScript أمرًا اختياريًا تمامًا، فهناك آراء مختلفة حول هذا الموضوع، وسنتحدث في هذا المقال بإيجاز عن إيجابيات وسلبيات استخدام هذه اللغة، إذ سيكون هذا المقال مفيدًا من خلال معرفة ما تقدمه لغة TypeScript ومساعدتك في اتخاذ قرارك حتى إذا لم تخطط لاستخدامها، فإذا لم تكن مهتمًا على الإطلاق باستخدام لغة TypeScript، فيمكنك تخطي هذا المقال والانتقال إلى المقال التالي حيث سنتعرّف على الخيارات المختلفة لنشر تطبيقات Svelte وموارد التعلم الإضافية وغير ذلك.
</p>

<p>
	يمكنك متابعة كتابة شيفرتك معنا، لذلك انسخ أولًا مستودع github -إذا لم تفعل ذلك مسبقًا- باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8867_10" style=""><span class="pln">git clone https</span><span class="pun">:</span><span class="com">//github.com/opensas/mdn-svelte-tutorial.git</span></pre>

<p>
	ثم يمكنك الوصول إلى حالة التطبيق الحالية من خلال تشغيل الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8867_12" style=""><span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">07</span><span class="pun">-</span><span class="pln">typescript</span><span class="pun">-</span><span class="pln">support</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8867_14" style=""><span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">07</span><span class="pun">-</span><span class="pln">typescript</span><span class="pun">-</span><span class="pln">support</span></pre>

<p>
	تذكَّر تشغيل الأمر <code>npm install &amp;&amp; npm run dev</code> لبدء تشغيل تطبيقك في وضع التطوير.
</p>

<p>
	<strong>ملاحظة</strong>: لا يتوفر دعم لغة TypeScript في أداة REPL حتى الآن لسوء الحظ.
</p>

<h2>
	لغة TypeScript: استخدام الأنواع الثابتة الاختيارية للغة جافاسكربت
</h2>

<p>
	تُعَدّ لغة TypeScript مشتقة من لغة جافاسكربت ومُوسِّعة لها إذ توفر ميزات مثل استخدام الأنواع الثابتة الاختيارية والأصناف والواجهات والأنواع المُعمَّمة Generics، فالهدف من TypeScript هو المساعدة في اكتشاف الأخطاء مبكرًا من خلال نظام الأنواع وجعل التطوير باستخدام <a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1689/" rel="">لغة جافاسكربت</a> أكثر كفاءةً، كما تتمثل إحدى الفوائد الكبيرة في تفعيل <a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D9%83%D8%A7%D9%85%D9%84%D8%A9-ide-r1513/" rel="">بيئات التطوير المتكاملة IDE</a> لتوفير بيئة لاكتشاف الأخطاء الشائعة أثناء كتابة الشيفرة البرمجية.
</p>

<p>
	أفضل ما في الأمر هو أنّ <a href="https://academy.hsoub.com/programming/javascript/%D9%86%D9%85%D8%B7-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%B4%D9%8A%D9%81%D8%B1%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r785/" rel="">شيفرة جافاسكربت</a> هي شيفرة TypeScript صالحة، إذ تُعَدّ لغة TypeScript مجموعةً من لغة جافاسكربت، ويمكنك إعادة تسمية معظم ملفات <code>‎.js</code> إلى ملفات <code>‎.ts</code> وستعمل مباشرةً، كما ستكون شيفرة TypeScript قادرةً على العمل في أيّ مكان يمكن أن تعمل فيه شيفرة جافاسكربت، إذ تترجِم لغة TypeScript شيفرتنا البرمجية إلى لغة جافاسكربت الصرفة Vanilla JavaScript، وهذا يعني أنها تحلّل شيفرة TypeScript وتنتج شيفرةً مكافئةً بلغة جافاسكربت الصرفة لتشغيلها على المتصفحات.
</p>

<p>
	<strong>ملاحظة</strong>: إذا كنت مهتمًا بمعرفة كيف تترجم لغة TypeScript الشيفرة البرمجية إلى لغة جافاسكربت، فيمكنك إلقاء نظرةً على <a href="https://www.typescriptlang.org/play?target=1#code/PTAEHUFMBsGMHsC2lQBd5oBYoCoE8AHSAZVgCcBLA1UA6AQzwHMz4BXAOwBMA6UHTBQDOoIRVQphoeqGjxUAWABQIWRQDWKMpw4UOTaf0IlyVGgVYArSLBp6xXFDIDukAEag3rZ0MhkeysqqAih0jCzs3KCI9Joi4qCQ9EJ4oABm8GSgeOxoGEL0aTCpkAAeRJTIHIoqYM7imKAUjslNHEZEpJTUnqkx6noGCaiUAG4U9NB5opj0ZJBBYKjYvrRWNqhCfCGgAKoASgAy6ZlYUgT0TJIikKN+eMuDi6DzAI5sFPNc03L038uhda2E5ZIRISDwDgoGC+AJKZQIDhCGjYaByUAAXlAACIABIwOTYgDcgVqoAAmrlYPR2r4UJCsFoKExMDQAS9IEI2NAaPA0oyOiZujVVAhEAQKNA-AAuM7xESjGmShigABS9EVXTMoGcglgjWp7W07Uhzy88B8fiEABpRH47mQRKcaXhdX4tEk0Xg4QjIcidZloN8sdjwIGuMTSapKWxQIa7ShMBamjR+py0HpUvqaVcROgBQhHLa3HhnoiHahBoZsYjkdjpjJsYqyNjtoJ5aBIfT+eyYhxS2THvoRPhOqYelx4On82mU7R4EIxG4pdNjc8XW75mqNfQtT1jVtSbX4FKeHImAAKVHogDUOPvd+c4YAlCT4WSAHLJ5b0Gg5WOzHc0jtM0SSdvySbOAKYTMKwnDfE+ZDqDazxSqgADkIhyPA6jSCiyajkK2ppiIiEDPoOoNM86qauOqaZCgaScHwAAibCUBRjwiL4tgUAyrjoWingoCMeBPIOGCaJABDSCIsByKs+aKroaIyDRu50bJ86LhQy4ifAzxCJBoDGf+cY0hyAC0bCrGUwiVhR6gcBaUpcFccIgM8ADC0AULAuFuDA34YIiDlsJA0qLM8ZT0OKUrSvAbjWLYQiWTSXBpWQZCMEIQA" rel="external nofollow">TypeScript Playground</a>.
</p>

<p>
	كان دعم TypeScript الميزة الأكثر طلبًا من <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">إطار عمل Svelte</a> لبعض الوقت، لذلك سنوضح لك في القسم التالي كيفية إعداد مشروع Svelte مع دعم TypeScript لتجربته.
</p>

<h2>
	فوائد لغة TypeScript
</h2>

<p>
	الفوائد الرئيسية للغة TypeScript هي:
</p>

<ul>
	<li>
		الرصد المبكر للزلات البرمجية والأخطاء: يتحقق المصرَّف Compiler من الأنواع في وقت التصريف ويقدم تقاريرًا بالأخطاء.
	</li>
	<li>
		قابلية القراءة: تمنح الأنواع الثابتة الشيفرة البرمجية بنيةً، مما يجعلها توثيقًا ذاتيًا وأكثر قابليةً للقراءة.
	</li>
	<li>
		الدعم الكبير لبيئة IDE: تسمح معلومات الأنواع لمحررات الشيفرة البرمجية وبيئات IDE بتقديم ميزات مثل التنقل في الشيفرة البرمجية والإكمال التلقائي والتلميحات الذكية.
	</li>
	<li>
		إعادة البناء الآمنة: تسمح الأنواع لبيئات IDE بمعرفة المزيد عن شيفرتك البرمجية، ومساعدتك أثناء إعادة بناء أجزاء كبيرة من قاعدة شيفرتك.
	</li>
	<li>
		استنتاج الأنواع: يمكنك الاستفادة من العديد من ميزات لغة TypeScript حتى بدون التصريح عن أنواع المتغيرات.
	</li>
	<li>
		توفير ميزات جافاسكربت الجديدة والمستقبلية: تنقل لغة TypeScript العديد من ميزات الإصدار ES6 الحديثة إلى لغة جافاسكربت القديمة، مما يسمح لك باستخدامها حتى مع وكلاء المستخدِمين الذين لا يدعمونها أصلًا حتى الآن.
	</li>
</ul>

<p>
	تحتوي لغة TypeScript على بعض العيوب هي:
</p>

<ul>
	<li>
		الأنواع الثابتة غير الصحيحة: تُختبَر الأنواع في وقت التصريف فقط، وتُزال من الشيفرة البرمجية المُنشَأة.
	</li>
	<li>
		المنحنى التعليمي الصعب: تُعَدّ لغة TypeScript صعبة التعلم بالرغم من أنها تُعَدّ مجموعةً من لغة جافاسكربت وليست لغة جديدةً تمامًا، خاصةً إذا لم يكن لديك خبرة على الإطلاق في اللغات الثابتة أو الساكنة مثل <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-java-r599/" rel="">جافا</a> أو <a href="https://academy.hsoub.com/programming/c-sharp/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-c-r597/" rel="">سي شارب C#</a>‎.
	</li>
	<li>
		مزيد من الشيفرة البرمجية: يجب كتابة مزيد من الشيفرة البرمجية والاحتفاظ بها.
	</li>
	<li>
		عدم وجود بديل للاختبارات الآلية: لا تُعَدّ لغة TypeScript بديلًا حقيقيًا لمجموعة شاملة من الاختبارات الآلية، بالرغم من أنّ الأنواع يمكنها مساعدك في اكتشاف العديد من الأخطاء.
	</li>
	<li>
		الشيفرة المتداولة Boilerplate: يمكن أن يؤدي العمل مع الأنواع والأصناف والواجهات والأنواع المُعمَّمة إلى قواعد شيفرة برمجية متداولة أو مكرَّرة كثيرًا.
	</li>
</ul>

<p>
	يبدو أنّ هناك إجماعًا واسعًا على أن لغة TypeScript مناسبة للمشاريع واسعة النطاق حيث يعمل العديد من المطورين على قاعدة الشيفرة البرمجية نفسها، إذ تستخدِمها حاليًا العديد من المشاريع الكبيرة مثل Angular 2 و Vue 3 و Ionic و Visual Studio Code و Jest ومصرِّف إطار Svelte، لكن يفضِّل بعض المطورين استخدامها في المشاريع الصغيرة أيضًا مثل المشروع الذي نطوّره حاليًا.
</p>

<h2>
	إنشاء مشروع Svelte باستخدام لغة TypeScript من الصفر
</h2>

<p>
	يمكنك بدء مشروع Svelte جديد باستخدام لغة TypeScript عبر <a href="https://github.com/sveltejs/template" rel="external nofollow">القالب المعياري</a>، إذ كل ما عليك فعله هو تشغيل أوامر الطرفية التالية التي يجب تشغيلها في المكان الذي تخزّن فيه مشاريع اختبار Svelte حيث سيُنشَأ مجلد جديد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8867_23" style=""><span class="pln">npx degit sveltejs</span><span class="pun">/</span><span class="pln">template svelte</span><span class="pun">-</span><span class="pln">typescript</span><span class="pun">-</span><span class="pln">app

cd svelte</span><span class="pun">-</span><span class="pln">typescript</span><span class="pun">-</span><span class="pln">app

node scripts</span><span class="pun">/</span><span class="pln">setupTypeScript</span><span class="pun">.</span><span class="pln">js</span></pre>

<p>
	تؤدي هذه الأوامر إلى إنشاء مشروع أولي يتضمن دعم TypeScript والذي يمكنك تعديله لاحقًا كما يحلو لك، كما يجب بعد ذلك إخبار <a href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AF%D9%8A%D8%B1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-npm-r1225/" rel="">مدير الحزم npm</a> بتنزيل الاعتماديات Dependencies وبدء المشروع في وضع التطوير كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8867_26" style=""><span class="pln">npm install

npm run dev</span></pre>

<h2>
	إضافة دعم TypeScript إلى مشروع Svelte قائم مسبقا
</h2>

<p>
	يمكنك إضافة دعم TypeScript إلى مشروع Svelte قائم من خلال اتباع <a href="https://svelte.dev/blog/svelte-and-typescript#Adding_TypeScript_to_an_existing_project" rel="external nofollow">هذه التعليمات</a>، أو يمكنك بدلًا من ذلك تنزيل ملف <a href="https://github.com/sveltejs/template/blob/master/scripts/setupTypeScript.js" rel="external nofollow">setupTypeScript.js</a> إلى المجلد scripts ضمن المجلد الجذر لمشروعك، ثم شغّل الأمر الآتي:
</p>

<pre class="ipsCode" id="ips_uid_8867_30"> node scripts/setupTypeScript.js</pre>

<p>
	كما يمكنك استخدام الأداة <code>degit</code> لتنزيل السكربت، وهذا ما سنفعله لبدء نقل تطبيقنا إلى لغة TypeScript.
</p>

<p>
	<strong>ملاحظة</strong>: تذكَّر أنه يمكنك تشغيل الأمر الآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8867_32" style=""><span class="pln"> npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">07</span><span class="pun">-</span><span class="pln">typescript</span><span class="pun">-</span><span class="pln">support svelte</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">typescript </span></pre>

<p>
	للحصول على تطبيق قائمة المهام الكامل بلغة جافاسكربت قبل البدء في نقله إلى لغة TypeScript.
</p>

<p>
	انتقل إلى المجلد الجذر للمشروع وأدخِل الأوامر التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8867_34" style=""><span class="pln">npx degit sveltejs</span><span class="pun">/</span><span class="pln">template</span><span class="pun">/</span><span class="pln">scripts scripts       </span><span class="pun">#</span><span class="pln"> </span><span class="pun">نزِّل</span><span class="pln"> </span><span class="pun">ملف</span><span class="pln"> </span><span class="pun">السكربت</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">مجلد</span><span class="pln"> </span><span class="pun">السكربتات</span><span class="pln">

node scripts</span><span class="pun">/</span><span class="pln">setupTypeScript</span><span class="pun">.</span><span class="pln">js                   </span><span class="pun">#</span><span class="pln"> </span><span class="pun">شغّله</span><span class="pln">
</span><span class="typ">Converted</span><span class="pln"> to </span><span class="typ">TypeScript</span><span class="pun">.</span></pre>

<p>
	كما يجب إعادة تشغيل مدير الاعتماديات للبدء.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8867_36" style=""><span class="pln">npm install                                       </span><span class="pun">#</span><span class="pln"> </span><span class="pun">نزّل</span><span class="pln"> </span><span class="pun">الاعتماديات</span><span class="pln"> </span><span class="pun">الجديدة</span><span class="pln">

npm run dev                                       </span><span class="pun">#</span><span class="pln"> </span><span class="pun">شغّل</span><span class="pln"> </span><span class="pun">التطبيق</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">وضع</span><span class="pln"> </span><span class="pun">التطوير</span></pre>

<p>
	تنطبق هذه التعليمات على أيّ مشروع Svelte ترغب في تحويله إلى لغة TypeScript، وضَع في الحسبان أنّ مجتمع Svelte يعمل باستمرار على تحسين دعم TypeScript في إطار عمل Svelte، لذلك يجب تشغيل الأمر <code>npm update</code> بانتظام للاستفادة من أحدث التغييرات.
</p>

<p>
	<strong>ملاحظة</strong>: إذا وجدت أيّ مشكلة في العمل مع TypeScript ضمن تطبيق Svelte، فألقِ نظرةً على <a href="https://github.com/sveltejs/language-tools/blob/master/docs/preprocessors/typescript.md#troubleshooting--faq" rel="external nofollow">قسم استكشاف الأخطاء وإصلاحها أو الأسئلة الشائعة حول دعم TypeScript</a>.
</p>

<p>
	تُعَدّ لغة TypeScript مشتقة من لغة جافاسكربت كما قلنا سابقًا، لذلك سيعمل تطبيقك بدون تعديلات، وستشغّل حاليًا تطبيق جافاسكربت عادي مع تفعيل دعم TypeScript دون الاستفادة من الميزات التي توفرها لغة TypeScript، ويمكنك الآن البدء في إضافة الأنواع تدريجيًا.
</p>

<p>
	يمكنك البدء في استخدام لغة TypeScript من مكونات Svelte بعد إعدادها من خلال إضافة <code>&lt;script lang='ts'‎&gt;</code> في بداية القسم <code>script</code>، وما عليك سوى تغيير امتداد الملف من <code>‎.js</code> إلى <code>‎.ts</code> لاستخدامه في ملفات جافاسكربت العادية. كما يجب تحديث أيّ تعليمات <code>import</code> استيراد مقابلة، إذ لا يجب أن تضمّن الامتداد <code>‎.ts</code> في تعليمات الاستيراد لأن لغة TypeScript تحذف الامتدادات.
</p>

<p>
	<strong>ملاحظة</strong>: استخدام TypeScript في أقسام توصيف Markup المكونات غير متاح حتى الآن، لذا يجب استخدام لغة جافاسكربت في التوصيف واستخدام لغة TypeScript في القسم <code>&lt;script lang='ts'‎&gt;</code>.
</p>

<h2>
	تحسين تجربة المطور باستخدام لغة TypeScript
</h2>

<p>
	توفِّر لغة TypeScript <a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%AD%D8%B1%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%B9%D9%85%D9%84%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1438/" rel="">محرّرات شيفرات برمجية</a> وبيئات IDE مع الكثير من المعلومات للسماح لها بتقديم تجربة تطوير أفضل، وسنستخدِم المحرر <a href="https://code.visualstudio.com/" rel="external nofollow">Visual Studio Code</a> لإجراء اختبار سريع ونرى كيف يمكننا الحصول على تلميحات الإكمال التلقائي وفحص الأنواع أثناء كتابة المكونات.
</p>

<p>
	<strong>ملاحظة</strong>: إذا لم ترغب في استخدام VS Code، فسنقدِّم إرشادات لاستخدام التحقق من أخطاء TypeScript من الطرفية بدلًا من ذلك لاحقًا.
</p>

<p>
	هناك عمل قيد التقدم لدعم TypeScript في مشاريع Svelte في العديد من محرّرات الشيفرات البرمجية، ولكن يتوفر الدعم الأكبر حتى الآن في الإضافة <a href="https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode" rel="external nofollow">Svelte for VS Code extension</a> التي يطورها ويعمل على صيانتها فريق Svelte، إذ توفر هذه الإضافة التحقق من الأنواع والفحص وإعادة البناء والتحسس الذكي للمساعدة على كتابة الشيفرة ومعلومات التمرير والإكمال التلقائي وميزات أخرى، حيث يُعَدّ هذا النوع من مساعدة المطورين سببًا وجيهًا آخر لبدء استخدام لغة TypeScript في مشاريعك.
</p>

<p>
	<strong>ملاحظة</strong>: تأكد من أنك تستخدِم الإضافة <a href="https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode" rel="external nofollow">Svelte for VS Code</a> وليس Svelte القديمة لصاحبها James Birtles التي جرى إيقافها، فإذا ثبّتها، فيجب عليك إلغاء تثبيتها وتثبيت إضافة Svelte الرسمية بدلًا من ذلك.
</p>

<p>
	لنفترض أنك ضمن تطبيق VS Code، اكتب <code>code .‎</code> من جذر مجلد مشروعك، حيث تخبر هذه النقطة اللاحقة شيفرة VS بفتح المجلد الحالي لفتح محرر الشيفرة البرمجية، كما سيخبرك المحرّر VS Code بوجود إضافات موصَى بها للتثبيت.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117042" href="https://academy.hsoub.com/uploads/monthly_2023_01/01-vscode-extension-recommendations.png.b3f5710a611788c78ba7163b3212ab99.png" rel=""><img alt="نافذة محرّر VS Code حول وجود إضافات موصَى بها للتثبيت" class="ipsImage ipsImage_thumbnailed" data-fileid="117042" data-ratio="22.74" data-unique="ddej8usfy" style="width: 475px; height: auto;" width="475" src="https://academy.hsoub.com/uploads/monthly_2023_01/01-vscode-extension-recommendations.png.b3f5710a611788c78ba7163b3212ab99.png"> </a>
</p>

<p>
	سيؤدي النقر على "تثبيت الكل Install all" إلى تثبيت الإضافة Svelte for VS Code.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117043" href="https://academy.hsoub.com/uploads/monthly_2023_01/02-svelte-for-vscode.png.1307b5fca239d32949ee49c3dfd9e199.png" rel=""><img alt="تثبيت الإضافة Svelte for VS Code" class="ipsImage ipsImage_thumbnailed" data-fileid="117043" data-ratio="20.26" data-unique="zkgvca6an" style="width: 780px; height: auto;" width="780" src="https://academy.hsoub.com/uploads/monthly_2023_01/02-svelte-for-vscode.thumb.png.edd40cf32edf8714d789b50280a6c64a.png"> </a>
</p>

<p>
	كما يمكننا أن نرى أنّ الملف setupTypeScript.js أجرى بعض التغييرات على مشروعنا، إذ أُعيدت تسمية الملف main.js إلى main.ts، مما يعني أنّ شيفرة VS يمكن أن توفر معلومات التمرير حول مكونات Svelte:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117045" href="https://academy.hsoub.com/uploads/monthly_2023_01/03-vscode-hints-in-main-ts.png.4e621a7674f1ec83f52ccccf5bead404.png" rel=""><img alt="إجراء الملف setupTypeScript.js لبعض التغييرات على المشروع" class="ipsImage ipsImage_thumbnailed" data-fileid="117045" data-ratio="59.79" data-unique="togikpsmi" style="width: 480px; height: auto;" width="480" src="https://academy.hsoub.com/uploads/monthly_2023_01/03-vscode-hints-in-main-ts.png.4e621a7674f1ec83f52ccccf5bead404.png"> </a>
</p>

<p>
	سنحصل على ميزة التحقق من الأنواع مجانًا، فإذا مررنا خاصيةً غير معروفة في معامِل الخيارات لدالة البناء <code>App</code> مثل كتابة الخطأ المطبعي <code>traget</code> بدلًا من <code>target</code>، فستعطي TypeScript خطأً كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117046" href="https://academy.hsoub.com/uploads/monthly_2023_01/04-vscode-type-checking-in-main-ts.png.36cc2061c56b7e992dda6addaa479bb6.png" rel=""><img alt="ميزة التحقق من الأنواع مجانًا في TypeScript" class="ipsImage ipsImage_thumbnailed" data-fileid="117046" data-ratio="30.90" data-unique="znfgd7pxw" style="width: 780px; height: auto;" width="750" src="https://academy.hsoub.com/uploads/monthly_2023_01/04-vscode-type-checking-in-main-ts.png.36cc2061c56b7e992dda6addaa479bb6.png"> </a>
</p>

<p>
	أضاف السكربت setupTypeScript.js في المكوِّن <code>App.svelte</code> السمة <code>lang="ts"‎</code> إلى الوسم <code>&lt;script&gt;</code>. كما لن نحتاج في كثير من الحالات لتحديد الأنواع للحصول على مساعدة الشيفرة البرمجية بفضل ميزة استنتاج الأنواع، فإذا أضفتَ الخاصية <code>ms</code> إلى استدعاء المكوِّن <code>Alert</code> مثلًا، فستستنتج لغة TypeScript من القيمة الافتراضية أنّ الخاصية <code>ms</code> يجب أن تكون عددًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117047" href="https://academy.hsoub.com/uploads/monthly_2023_01/05-vscode-type-inference-and-code-assistance.png.59b60bdc07c16df16e6a9976af03a2fa.png" rel=""><img alt="إضافة الخاصية ms إلى استدعاء المكوِّن Alert" class="ipsImage ipsImage_thumbnailed" data-fileid="117047" data-ratio="46.03" data-unique="bcfeh14sa" style="width: 780px; height: auto;" width="842" src="https://academy.hsoub.com/uploads/monthly_2023_01/05-vscode-type-inference-and-code-assistance.png.59b60bdc07c16df16e6a9976af03a2fa.png"> </a>
</p>

<p>
	وإذا مرّرت شيئًا ليس عددًا، فسيظهر خطأ كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117048" href="https://academy.hsoub.com/uploads/monthly_2023_01/06-vscode-type-checking-in-components.png.68d91f7787bdc998b1669d8193491ef9.png" rel=""><img alt="ميزة استنتاج الأنواع في TypeScript" class="ipsImage ipsImage_thumbnailed" data-fileid="117048" data-ratio="34.77" data-unique="zu14wulck" style="width: 650px; height: auto;" width="678" src="https://academy.hsoub.com/uploads/monthly_2023_01/06-vscode-type-checking-in-components.png.68d91f7787bdc998b1669d8193491ef9.png"> </a>
</p>

<p>
	يحتوي قالب التطبيق على سكربت تحقق <code>check</code> مُعَدّ لتشغيل أداة <code>svelte-check</code> للتحقق من شيفرتك البرمجية، إذ تسمح هذه الحزمة باكتشاف الأخطاء والتحذيرات التي يعرضها محرر الشيفرات البرمجية من سطر الأوامر، مما يجعلها مفيدة جدًا لتشغيلها في خط أنابيب تكامل مستمر continuous integration أو CI اختصارًا، لذا شغّل الأمر <code>npm run check</code> لفحص أجزاء شيفرة <a href="https://academy.hsoub.com/programming/css/%d8%aa%d8%b9%d8%b1%d9%91%d9%81-%d8%b9%d9%84%d9%89-%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d8%a7%d8%aa-css-r70/" rel="">CSS</a> غير المُستخدَمة، وإعادة تلميحات الشمولية A11y وأخطاء تصريف شيفرة TypeScript.
</p>

<p>
	إذا شغّلتَ الأمر <code>npm run check</code> في هذه الحالة في طرفية VS Code أو طرفية جهازك، فسيظهر الخطأ التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117049" href="https://academy.hsoub.com/uploads/monthly_2023_01/07-vscode-svelte-check.png.ee7e4ed12bba07c6b1dd7229438745b9.png" rel=""><img alt="تشغيل الأمر npm run check  في طرفية VS Code " class="ipsImage ipsImage_thumbnailed" data-fileid="117049" data-ratio="63.69" data-unique="d9c5958hz" style="width: 650px; height: auto;" width="753" src="https://academy.hsoub.com/uploads/monthly_2023_01/07-vscode-svelte-check.png.ee7e4ed12bba07c6b1dd7229438745b9.png"> </a>
</p>

<p>
	وإذا شغّلته من الطرفية المدمجة في VS Code التي يمكنك فتحها باستخدام الاختصار "<code>Ctrl + `‎</code>"، فسينقلك الضغط مع المفتاح <code>Cmd</code> أو <code>Ctrl</code> على اسم الملف إلى السطر الذي يحتوي على الخطأ.
</p>

<p>
	كما يمكنك تشغيل سكربت التحقق <code>check</code> في وضع المراقبة باستخدام الأمر <code>npm run check -- --watch</code>، حيث سيُنفَّذ السكربت في هذه الحالة كلما عدّلتَ ملفًا، فإذا شغّلتَ هذا الأمر في الطرفية العادية، فاجعلها تعمل في الخلفية في نافذة طرفية منفصلة بحيث يمكنها الاستمرار في الإبلاغ عن الأخطاء ولكنها لن تتداخل مع استخدام طرفية أخرى.
</p>

<h2>
	إنشاء نوع مخصص
</h2>

<p>
	تدعم لغة TypeScript الأنواع البنيوية، والتي هي طريقة لربط الأنواع بناءً على عناصرها فقط، حتى إذا لم تحدد النوع صراحةً، وسنعرِّف النوع <code>TodoType</code> لنرى كيف تفرض لغة TypeScript أنّ أيّ شيء يُمرَّر إلى مكوِّن يتوقع أن يكون من النوع <code>TodoType</code> يجب أن يكون متوافقًا بنيويًا معه.
</p>

<p>
	أنشئ المجلد types ضمن المجلد src، ثم أضف الملف todo.type.ts ضمنه وضع المحتوى التالي فيه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_23" style=""><span class="kwd">export</span><span class="pln"> type </span><span class="typ">TodoType</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> number
  name</span><span class="pun">:</span><span class="pln"> string
  completed</span><span class="pun">:</span><span class="pln"> boolean
</span><span class="pun">}</span></pre>

<p>
	<strong>ملاحظة</strong>: يستخدِم قالبُ Svelte المعالجَ المُسبَق <a href="https://github.com/sveltejs/svelte-preprocess" rel="external nofollow"> svelte-preprocess 4.0.0</a> لدعم لغة TypeScript، كما يجب استخدام صيغة الأنواع <code>export/import</code> لاستيراد الأنواع والواجهات من هذا الإصدار فصاعدًا.
</p>

<p>
	سنستخدِم الآن النوع <code>TodoType</code> في المكوِّن <code>Todo.svelte</code>، لذا أضِف أولًا السمة <code>lang="ts"‎</code> إلى الوسم <code>&lt;script&gt;</code>، لنستورد النوع ولنستخدِمه للتصريح عن الخاصية <code>todo</code>، لذا استبدل السطر <code>export let todo</code> بما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_25" style=""><span class="kwd">import</span><span class="pln"> type </span><span class="pun">{</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../types/todo.type"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> todo</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">;</span></pre>

<p>
	<strong>ملاحظة</strong>: تذكّر أنه يجب حذف الامتداد عند استيراد ملف <code>‎.ts</code>.
</p>

<p>
	سننشئ الآن نسخةً من المكوِّن <code>Todo</code> من الملف <code>Todos.svelte</code> مع كائن حرفي بوصفه معامِلًا قبل استدعاء المكوِّن <code>MoreActions</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9012_27" style=""><span class="tag">&lt;hr</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">

</span><span class="tag">&lt;Todo</span><span class="pln"> </span><span class="atn">todo</span><span class="pun">=</span><span class="atv">{</span><span class="pln"> { </span><span class="atn">name</span><span class="pln">: </span><span class="atv">'a new task with no id!'</span><span class="pln">, </span><span class="atn">completed</span><span class="pln">: </span><span class="atn">false</span><span class="pln"> } } </span><span class="tag">/&gt;</span><span class="pln">

</span><span class="com">&lt;!-- MoreActions --&gt;</span><span class="pln">
&lt;MoreActions {todos}</span></pre>

<p>
	أضف السمة <code>lang='ts'‎</code> إلى الوسم <code>&lt;script&gt;</code> الخاص بالمكوِّن <code>Todos.svelte</code> لمعرفة كيفية استخدام التحقق من الأنواع الذي حددناه، ولكن سنحصل على الخطأ التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117050" href="https://academy.hsoub.com/uploads/monthly_2023_01/08-vscode-structural-typing.png.bd8f0e3d45da24c2314787830cbe1cf7.png" rel=""><img alt="إضافة lang='ts'‎ إلى &lt;script&gt; لمكوِّن Todos.svelte " class="ipsImage ipsImage_thumbnailed" data-fileid="117050" data-ratio="20.90" data-unique="fhqh8nz1v" style="width: 780px; height: auto;" width="780" src="https://academy.hsoub.com/uploads/monthly_2023_01/08-vscode-structural-typing.thumb.png.afd6b7d8d92d218d14663122e3f8fd0b.png"> </a>
</p>

<p>
	يجب الآن أن تحصل على فكرة حول نوع المساعدة التي يمكننا الحصول عليها من لغة TypeScript عند إنشاء مشاريع Svelte، وسنتراجع الآن عن هذه التغييرات من أجل البدء في نقل تطبيقنا إلى لغة TypeScript، لذلك لن نشعر بالانزعاج من جميع تحذيرات التحقق.
</p>

<ol>
	<li>
		أزِل المهمة التي تسبب الأخطاء والسمة <code>lang='ts'‎</code> من الملف Todos.svelte.
	</li>
	<li>
		أزِل استيراد النوع <code>TodoType</code> والسمة <code>lang='ts'‎</code> من الملف Todos.svelte.
	</li>
</ol>

<h2>
	نقل تطبيق قائمة المهام إلى لغة TypeScript
</h2>

<p>
	أصبحنا الآن جاهزين لبدء نقل تطبيق قائمة المهام للاستفادة من جميع الميزات التي توفرها لغة TypeScript. لنبدأ بتشغيل سكربت التحقق في وضع المراقبة ضمن جذر المشروع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_30" style=""><span class="pln">npm run check </span><span class="pun">--</span><span class="pln"> </span><span class="pun">--</span><span class="pln">watch</span></pre>

<p>
	يجب أن ينتج ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_32" style=""><span class="pln">svelte</span><span class="pun">-</span><span class="pln">check </span><span class="str">"--watch"</span><span class="pln">

</span><span class="typ">Loading</span><span class="pln"> svelte</span><span class="pun">-</span><span class="pln">check in workspace</span><span class="pun">:</span><span class="pln"> </span><span class="pun">./</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">typescript
</span><span class="typ">Getting</span><span class="pln"> </span><span class="typ">Svelte</span><span class="pln"> diagnostics</span><span class="pun">...</span><span class="pln">
</span><span class="pun">====================================</span><span class="pln">
svelte</span><span class="pun">-</span><span class="pln">check found no errors and no warnings</span></pre>

<p>
	لاحظ أنه إذا استخدَمتَ محرر شيفرات داعم مثل المحرّر VS Code، فستكون الطريقة البسيطة لبدء نقل مكوِّن Svelte هي بإضافة <code>&lt;script lang='ts'‎&gt;</code> فقط في أعلى المكوِّن والبحث عن تلميحات ثلاثية النقاط كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117051" href="https://academy.hsoub.com/uploads/monthly_2023_01/09-vscode-alert-hints.png.a7a4b01272e05330abd1e7d5ec15173a.png" rel=""><img alt="استخدام محرر شيفرات" class="ipsImage ipsImage_thumbnailed" data-fileid="117051" data-ratio="41.28" data-unique="lpj10tjvm" style="width: 780px; height: auto;" width="780" src="https://academy.hsoub.com/uploads/monthly_2023_01/09-vscode-alert-hints.thumb.png.3fbb472a5ff17d51ed35ab49fafe6ff0.png"> </a>
</p>

<h3>
	المكون Alert.svelte
</h3>

<p>
	لنبدأ بالمكوِّن <code>Alert.svelte</code>.
</p>

<p>
	أضِف السمة <code>lang="ts"‎</code> إلى الوسم <code>&lt;script&gt;</code> الخاص بالمكوِّن <code>Alert.svelte</code>، إذ سترى بعض التحذيرات في خرج السكربت <code>check</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_35" style=""><span class="pln">$ npm run check </span><span class="pun">--</span><span class="pln"> </span><span class="pun">--</span><span class="pln">watch
</span><span class="pun">&gt;</span><span class="pln"> svelte</span><span class="pun">-</span><span class="pln">check </span><span class="str">"--watch"</span><span class="pln">

</span><span class="pun">./</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">typescript
</span><span class="typ">Getting</span><span class="pln"> </span><span class="typ">Svelte</span><span class="pln"> diagnostics</span><span class="pun">...</span><span class="pln">
</span><span class="pun">====================================</span><span class="pln">

</span><span class="pun">./</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">typescript</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="pln">components</span><span class="pun">/</span><span class="typ">Alert</span><span class="pun">.</span><span class="pln">svelte</span><span class="pun">:</span><span class="lit">8</span><span class="pun">:</span><span class="lit">7</span><span class="pln">
</span><span class="typ">Warn</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Variable</span><span class="pln"> </span><span class="str">'visible'</span><span class="pln"> implicitly has an </span><span class="str">'any'</span><span class="pln"> type</span><span class="pun">,</span><span class="pln"> but a better type may be inferred from usage</span><span class="pun">.</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ts</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> visible

</span><span class="pun">./</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">typescript</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="pln">components</span><span class="pun">/</span><span class="typ">Alert</span><span class="pun">.</span><span class="pln">svelte</span><span class="pun">:</span><span class="lit">9</span><span class="pun">:</span><span class="lit">7</span><span class="pln">
</span><span class="typ">Warn</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Variable</span><span class="pln"> </span><span class="str">'timeout'</span><span class="pln"> implicitly has an </span><span class="str">'any'</span><span class="pln"> type</span><span class="pun">,</span><span class="pln"> but a better type may be inferred from usage</span><span class="pun">.</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ts</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> timeout

</span><span class="pun">./</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">typescript</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="pln">components</span><span class="pun">/</span><span class="typ">Alert</span><span class="pun">.</span><span class="pln">svelte</span><span class="pun">:</span><span class="lit">11</span><span class="pun">:</span><span class="lit">28</span><span class="pln">
</span><span class="typ">Warn</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Parameter</span><span class="pln"> </span><span class="str">'message'</span><span class="pln"> implicitly has an </span><span class="str">'any'</span><span class="pln"> type</span><span class="pun">,</span><span class="pln"> but a better type may be inferred from usage</span><span class="pun">.</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ts</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Change</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">message</span><span class="pun">,</span><span class="pln"> ms</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

</span><span class="pun">./</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">typescript</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="pln">components</span><span class="pun">/</span><span class="typ">Alert</span><span class="pun">.</span><span class="pln">svelte</span><span class="pun">:</span><span class="lit">11</span><span class="pun">:</span><span class="lit">37</span><span class="pln">
</span><span class="typ">Warn</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Parameter</span><span class="pln"> </span><span class="str">'ms'</span><span class="pln"> implicitly has an </span><span class="str">'any'</span><span class="pln"> type</span><span class="pun">,</span><span class="pln"> but a better type may be inferred from usage</span><span class="pun">.</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ts</span><span class="pun">)</span><span class="pln">
</span><span class="pun">(</span><span class="pln">message</span><span class="pun">,</span><span class="pln"> ms</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	يمكنك إصلاح هذه التحذيرات من خلال تحديد الأنواع المقابلة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_37" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> ms </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3000</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> visible</span><span class="pun">:</span><span class="pln"> boolean
  </span><span class="kwd">let</span><span class="pln"> timeout</span><span class="pun">:</span><span class="pln"> number

  </span><span class="kwd">const</span><span class="pln"> onMessageChange </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">message</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">,</span><span class="pln"> ms</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    clearTimeout</span><span class="pun">(</span><span class="pln">timeout</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">message</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">               </span><span class="com">// إخفاء التنبيه إذا كانت الرسالة فارغة</span></pre>

<p>
	<strong>ملاحظة</strong>: ليست هناك حاجة لتحديد نوع <code>ms</code> في التعليمة <code>export let ms:number = 3000</code>، لأن لغة TypeScript تستنتجه مباشرةً من قيمته الافتراضية.
</p>

<h3>
	المكون MoreActions.svelte
</h3>

<p>
	سنطبّق الآن الشيء نفسه على المكوِّن <code>MoreActions.svelte</code>.
</p>

<p>
	أضِف السمة <code>lang='ts'‎</code>، وستحذِّرنا لغة TypeScript من الخاصية <code>todos</code> والمتغير <code>t</code> في الاستدعاء <code>todos.filter((t) =&gt;...)‎</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_39" style=""><span class="typ">Warn</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Variable</span><span class="pln"> </span><span class="str">'todos'</span><span class="pln"> implicitly has an </span><span class="str">'any'</span><span class="pln"> type</span><span class="pun">,</span><span class="pln"> but a better type may be inferred from usage</span><span class="pun">.</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ts</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> todos

</span><span class="typ">Warn</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Parameter</span><span class="pln"> </span><span class="str">'t'</span><span class="pln"> implicitly has an </span><span class="str">'any'</span><span class="pln"> type</span><span class="pun">,</span><span class="pln"> but a better type may be inferred from usage</span><span class="pun">.</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ts</span><span class="pun">)</span><span class="pln">
  $</span><span class="pun">:</span><span class="pln"> completedTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">).</span><span class="pln">length</span></pre>

<p>
	سنستخدِم النوع <code>TodoType</code> الذي عرّفناه سابقًا لإعلام لغة TypeScript أنّ الخاصية <code>todos</code> هي مصفوفة <code>TodoType</code>، لذا استبدل <code>export let todos</code> بما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_41" style=""><span class="kwd">import</span><span class="pln"> type </span><span class="pun">{</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../types/todo.type"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> todos</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">[];</span></pre>

<p>
	لاحظ أنّ لغة TypeScript يمكنها الآن أن تستنتج أنّ المتغير <code>t</code> في الاستدعاء <code>todos.filter(t =&gt; t.completed)‎</code> من النوع <code>TodoType</code>، ولكن يمكننا تحديده كما يلي إذا اعتقدنا أنّ ذلك يسهل قراءة شيفرتنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_43" style=""><span class="pln">$</span><span class="pun">:</span><span class="pln"> completedTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">t</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">).</span><span class="pln">length</span><span class="pun">;</span></pre>

<p>
	ستكون لغة TypeScript قادرةً على استنتاج نوع المتغير التفاعلي بصورة صحيحة، ولكن يمكن أن يظهر الخطأ "implicitly has an 'any' type" عند العمل مع الإسنادات التفاعلية، لذا يمكنك في هذه الحالات التصريح عن نوع المتغير في تعليمة مختلفة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_45" style=""><span class="kwd">let</span><span class="pln"> completeTodos</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
$</span><span class="pun">:</span><span class="pln"> completedTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">t</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">).</span><span class="pln">length</span><span class="pun">;</span></pre>

<p>
	لا يمكنك تحديد النوع في الإسناد التفاعلي نفسه، فالتعليمة التالي غير صالحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_47" style=""><span class="pun">‎</span><span class="pln">$</span><span class="pun">:</span><span class="pln"> completedTodos</span><span class="pun">:</span><span class="pln"> number </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">[...]‎</span></pre>

<h3>
	المكون FilterButton.svelte
</h3>

<p>
	أضف السمة <code>lang='ts'‎</code> إلى الوسم <code>&lt;script&gt;</code> مثل العادة وستلاحظ عدم وجود تحذيرات، إذ تستنتج لغة TypeScript نوع متغير الترشيح filter من قيمته الافتراضية، ولكننا نعلم أنه يملك ثلاث قيم صالحة فقط هي: جميع المهام all والمهام النشط active والمهام المكتملة completed، حيث يمكننا السماح للغة TypeScript بالتعرف على هذه القيم من خلال إنشاء مُرشح filter من النوع <a href="https://wiki.hsoub.com/TypeScript/enums" rel="external">الثوابت المتعددة <code>enum</code></a>.
</p>

<p>
	أنشئ بعدها ملفًا بالاسم filter.enum.ts في المجلد types، وضع فيه المحتويات التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_50" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">Filter</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  ALL </span><span class="pun">=</span><span class="pln"> </span><span class="str">'all'</span><span class="pun">,</span><span class="pln">
  ACTIVE </span><span class="pun">=</span><span class="pln"> </span><span class="str">'active'</span><span class="pun">,</span><span class="pln">
  COMPLETED </span><span class="pun">=</span><span class="pln"> </span><span class="str">'completed'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنستخدِم ذلك الآن في المكوِّن <code>FilterButton</code>، لذا استبدل محتوى الملف FilterButton.svelte بما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_52" style=""><span class="pun">&lt;!--</span><span class="pln"> components</span><span class="pun">/</span><span class="typ">FilterButton</span><span class="pun">.</span><span class="pln">svelte </span><span class="pun">--&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">script lang</span><span class="pun">=</span><span class="str">'ts'</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Filter</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../types/filter.enum'</span><span class="pln">

  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> filter</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Filter</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ALL
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"filters btn-group stack-exception"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">button </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"btn toggle-btn"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">:</span><span class="pln">btn__primary</span><span class="pun">={</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ALL</span><span class="pun">}</span><span class="pln"> aria</span><span class="pun">-</span><span class="pln">pressed</span><span class="pun">={</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ALL</span><span class="pun">}</span><span class="pln"> on</span><span class="pun">:</span><span class="pln">click</span><span class="pun">={()=&gt;</span><span class="pln"> filter </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ALL</span><span class="pun">}</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"visually-hidden"</span><span class="pun">&gt;</span><span class="typ">Show</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">span</span><span class="pun">&gt;</span><span class="typ">All</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"visually-hidden"</span><span class="pun">&gt;</span><span class="pln">tasks</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">button </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"btn toggle-btn"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">:</span><span class="pln">btn__primary</span><span class="pun">={</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ACTIVE</span><span class="pun">}</span><span class="pln"> aria</span><span class="pun">-</span><span class="pln">pressed</span><span class="pun">={</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ACTIVE</span><span class="pun">}</span><span class="pln"> on</span><span class="pun">:</span><span class="pln">click</span><span class="pun">={()=&gt;</span><span class="pln"> filter </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ACTIVE</span><span class="pun">}</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"visually-hidden"</span><span class="pun">&gt;</span><span class="typ">Show</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">span</span><span class="pun">&gt;</span><span class="typ">Active</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"visually-hidden"</span><span class="pun">&gt;</span><span class="pln">tasks</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">button </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"btn toggle-btn"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">:</span><span class="pln">btn__primary</span><span class="pun">={</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">COMPLETED</span><span class="pun">}</span><span class="pln"> aria</span><span class="pun">-</span><span class="pln">pressed</span><span class="pun">={</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">COMPLETED</span><span class="pun">}</span><span class="pln"> on</span><span class="pun">:</span><span class="pln">click</span><span class="pun">={()=&gt;</span><span class="pln"> filter </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">COMPLETED</span><span class="pun">}</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"visually-hidden"</span><span class="pun">&gt;</span><span class="typ">Show</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">span</span><span class="pun">&gt;</span><span class="typ">Completed</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"visually-hidden"</span><span class="pun">&gt;</span><span class="pln">tasks</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span></pre>

<p>
	استوردنا فقط المرشح <code>Filter</code> من النوع <code>enum</code> واستخدمناه بدلًا من قيم السلاسل النصية التي استخدمناها سابقًا.
</p>

<h3>
	المكون Todos.svelte
</h3>

<p>
	سنستخدِم المرشح <code>Filter</code> من النوع <code>enum</code> في المكوِّن <code>Todos.svelte</code>.
</p>

<p>
	أضِف أولًا السمة <code>lang='ts'‎</code> إليه، ثم استورد المرشح <code>Filter</code> من النوع <code>enum</code>، لذا أضِف تعليمة الاستيراد التالية بعد تعليمات الاستيراد الموجودة مسبقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_54" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Filter</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../types/filter.enum"</span><span class="pun">;</span></pre>

<p>
	سنستخدِمه الآن في أيّ مكان نشير فيه إلى المرشّح Filter الحالي، لذا استبدل الكتلتين المتعلقتين به بما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_56" style=""><span class="kwd">let</span><span class="pln"> filter</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Filter</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ALL</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> filterTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">filter</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">,</span><span class="pln"> todos</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln">
  filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ACTIVE
    </span><span class="pun">?</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">:</span><span class="pln"> filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">COMPLETED
    </span><span class="pun">?</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">:</span><span class="pln"> todos</span><span class="pun">;</span><span class="pln">

$</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ALL</span><span class="pun">)</span><span class="pln"> $alert </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Browsing all todos"</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ACTIVE</span><span class="pun">)</span><span class="pln"> $alert </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Browsing active todos"</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">COMPLETED</span><span class="pun">)</span><span class="pln"> $alert </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Browsing completed todos"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيظل السكربت <code>check</code> يعطينا بعض التحذيرات من المكوِّن <code>Todos.svelte</code>، فلنصلح ذلك من خلال استيراد النوع <code>TodoType</code> وإعلام لغة TypeScript أنّ المتغير <code>todos</code> هو مصفوفة من النوع <code>TodoType</code>، لذا استبدل السطر <code>export let todos = []‎</code> بالسطرين التاليين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_58" style=""><span class="kwd">import</span><span class="pln"> type </span><span class="pun">{</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../types/todo.type"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> todos</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span></pre>

<p>
	سنحدّد بعد ذلك جميع الأنواع المفقودة، إذ يُعَدّ المتغير <code>todosStatus</code> -الذي استخدمناه للوصول برمجيًا إلى التوابع التي يمكن الوصول إليها من المكوِّن <code>TodosStatus</code>- من النوع <code>TodosStatus</code>، كما ستكون كل مهمة <code>todo</code> من النوع <code>TodoType</code>، لذا عدّل القسم <code>&lt;script&gt;</code> ليبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_60" style=""><span class="pun">&lt;</span><span class="pln">script lang</span><span class="pun">=</span><span class="str">'ts'</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">FilterButton</span><span class="pln"> from </span><span class="str">'./FilterButton.svelte'</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Todo</span><span class="pln"> from </span><span class="str">'./Todo.svelte'</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">MoreActions</span><span class="pln"> from </span><span class="str">'./MoreActions.svelte'</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">NewTodo</span><span class="pln"> from </span><span class="str">'./NewTodo.svelte'</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">TodosStatus</span><span class="pln"> from </span><span class="str">'./TodosStatus.svelte'</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../stores'</span><span class="pln">

  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Filter</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../types/filter.enum'</span><span class="pln">

  </span><span class="kwd">import</span><span class="pln"> type </span><span class="pun">{</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../types/todo.type'</span><span class="pln">

  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> todos</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> todosStatus</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodosStatus</span><span class="pln">                   </span><span class="com">//  ‫مرجع إلى نسخة TodosStatus </span><span class="pln">

  $</span><span class="pun">:</span><span class="pln"> newTodoId </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(...</span><span class="pln">todos</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">

  </span><span class="kwd">function</span><span class="pln"> addTodo</span><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    todos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[...</span><span class="pln">todos</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> newTodoId</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}]</span><span class="pln">
    $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Todo</span><span class="pln"> </span><span class="str">'${name}'</span><span class="pln"> has been added</span><span class="pun">`</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">function</span><span class="pln"> removeTodo</span><span class="pun">(</span><span class="pln">todo</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    todos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
    todosStatus</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">()</span><span class="pln">             </span><span class="com">// نقل التركيز إلى عنوان الحالة</span><span class="pln">
    $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Todo</span><span class="pln"> </span><span class="str">'${todo.name}'</span><span class="pln"> has been deleted</span><span class="pun">`</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">function</span><span class="pln"> updateTodo</span><span class="pun">(</span><span class="pln">todo</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">findIndex</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">todos</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">name </span><span class="pun">!==</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">            $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">todo </span><span class="str">'${todos[i].name}'</span><span class="pln"> has been renamed to </span><span class="str">'${todo.name}'</span><span class="pun">`</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">todos</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">completed </span><span class="pun">!==</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">)</span><span class="pln">  $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">todo </span><span class="str">'${todos[i].name}'</span><span class="pln"> marked as $</span><span class="pun">{</span><span class="pln">todo</span><span class="pun">.</span><span class="pln">completed </span><span class="pun">?</span><span class="pln"> </span><span class="str">'completed'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'active'</span><span class="pun">}`</span><span class="pln">
    todos</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">todos</span><span class="pun">[</span><span class="pln">i</span><span class="pun">],</span><span class="pln"> </span><span class="pun">...</span><span class="pln">todo </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> filter</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Filter</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ALL
  </span><span class="kwd">const</span><span class="pln"> filterTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">filter</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">,</span><span class="pln"> todos</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">[])</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln">
    filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ACTIVE </span><span class="pun">?</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln">
    filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">COMPLETED </span><span class="pun">?</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln">
    todos

  $</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ALL</span><span class="pun">)</span><span class="pln">               $alert </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Browsing all todos'</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">ACTIVE</span><span class="pun">)</span><span class="pln">       $alert </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Browsing active todos'</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Filter</span><span class="pun">.</span><span class="pln">COMPLETED</span><span class="pun">)</span><span class="pln">    $alert </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Browsing completed todos'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> checkAllTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">completed</span><span class="pun">:</span><span class="pln"> boolean</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    todos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">({...</span><span class="pln">t</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">}))</span><span class="pln">
    $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">completed </span><span class="pun">?</span><span class="pln"> </span><span class="str">'Checked'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'Unchecked'</span><span class="pun">}</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">todos</span><span class="pun">.</span><span class="pln">length</span><span class="pun">}</span><span class="pln"> todos</span><span class="pun">`</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> removeCompletedTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Removed</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">).</span><span class="pln">length</span><span class="pun">}</span><span class="pln"> todos</span><span class="pun">`</span><span class="pln">
    todos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<h3>
	المكون TodosStatus.svelte
</h3>

<p>
	نواجه الأخطاء التالية المتعلقة بتمرير <code>todos</code> إلى المكوِّنين <code>TodosStatus.svelte</code> و <code>Todo.svelte</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_62" style=""><span class="pun">.</span><span class="str">/src/</span><span class="pln">components</span><span class="pun">/</span><span class="typ">Todos</span><span class="pun">.</span><span class="pln">svelte</span><span class="pun">:</span><span class="lit">70</span><span class="pun">:</span><span class="lit">39</span><span class="pln">
</span><span class="typ">Error</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="str">'TodoType[]'</span><span class="pln"> is not assignable to type </span><span class="str">'undefined'</span><span class="pun">.</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ts</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">TodosStatus</span><span class="pln"> bind</span><span class="pun">:</span><span class="kwd">this</span><span class="pun">={</span><span class="pln">todosStatus</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">todos</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

</span><span class="pun">./</span><span class="pln">src</span><span class="pun">/</span><span class="pln">components</span><span class="pun">/</span><span class="typ">Todos</span><span class="pun">.</span><span class="pln">svelte</span><span class="pun">:</span><span class="lit">76</span><span class="pun">:</span><span class="lit">12</span><span class="pln">
</span><span class="typ">Error</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="str">'TodoType'</span><span class="pln"> is not assignable to type </span><span class="str">'undefined'</span><span class="pun">.</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ts</span><span class="pun">)</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="typ">Todo</span><span class="pln"> </span><span class="pun">{</span><span class="pln">todo</span><span class="pun">}</span></pre>

<p>
	تظهر هذه الأخطاء لأن الخاصية <code>todos</code> في المكوِّن <code>TodosStatus</code> ليس لها قيمة افتراضية، لذلك استنتجت لغة TypeScript أنها من النوع غير المعرَّف <code>undefined</code>، وهو غير متوافق مع مصفوفة من النوع <code>TodoType</code>، كما يحدث الشيء نفسه مع المكوِّن <code>Todo</code>، إذًا لنصلح هذه الأخطاء.
</p>

<p>
	افتح الملف TodosStatus.svelte وأضِف السمة <code>lang='ts'‎</code> ثم استورد النوع <code>TodoType</code> وصرّح عن الخاصية <code>todos</code> على أنها مصفوفة من النوع <code>TodoType</code>، لذا استبدل السطر الأول من القسم <code>&lt;script&gt;</code> بما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_64" style=""><span class="kwd">import</span><span class="pln"> type </span><span class="pun">{</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../types/todo.type"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> todos</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">[];</span></pre>

<p>
	كما سنحدّد المتغير <code>headingEl</code> -الذي استخدمناه لربط وسم العنوان- بوصفه من النوع <code>HTMLElement</code>، لذا عدّل السطر <code>let headingEl</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_66" style=""><span class="kwd">let</span><span class="pln"> headingEl</span><span class="pun">:</span><span class="pln"> </span><span class="typ">HTMLElement</span><span class="pun">;</span></pre>

<p>
	أخيرًا، ستلاحظ الخطأ التالي المتعلق بالمكان الذي ضبطنا فيه السمة <code>tabindex</code>، لأن لغة TypeScript تتحقق من نوع <a href="https://wiki.hsoub.com/HTML/h1-h6" rel="external">العنصر &lt;h2&gt;</a> وتتوقع أن تكون السمة <code>tabindex</code> من النوع العددي <code>number</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117052" href="https://academy.hsoub.com/uploads/monthly_2023_01/10-vscode-tabindex-hint.png.58275eadad9ff90bf03d391421581639.png" rel=""><img alt="تحقق لغة TypeScript من نوع العنصر &lt;h2&gt;" class="ipsImage ipsImage_thumbnailed" data-fileid="117052" data-ratio="22.95" data-unique="2t2br1ngm" style="width: 780px; height: auto;" width="780" src="https://academy.hsoub.com/uploads/monthly_2023_01/10-vscode-tabindex-hint.thumb.png.4bf9618e019156a412c73d7a1bec2897.png"> </a>
</p>

<p>
	يمكن إصلاح هذا الخطأ من خلال استبدال <code>tabindex="-1"‎</code> بالشكل <code>tabindex={-1}‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_69" style=""><span class="pun">&lt;</span><span class="pln">h2 id</span><span class="pun">=</span><span class="str">"list-heading"</span><span class="pln"> bind</span><span class="pun">:</span><span class="kwd">this</span><span class="pun">=</span><span class="str">"{headingEl}"</span><span class="pln"> tabindex</span><span class="pun">=</span><span class="str">"{-1}"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">completedTodos</span><span class="pun">}</span><span class="pln"> out </span><span class="kwd">of</span><span class="pln"> </span><span class="pun">{</span><span class="pln">totalTodos</span><span class="pun">}</span><span class="pln"> items completed
</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span></pre>

<p>
	يمكن أن تمنعنا لغة TypeScript باستخدام هذه الطريقة من إسناد هذه السمة إلى متغير من نوع السلسلة النصية بصورة غير صحيحة.
</p>

<h3>
	المكون NewTodo.svelte
</h3>

<p>
	أضِف السمة <code>lang='ts'‎</code> مثل العادة، حيث سيشير التحذير إلى أنه يجب تحديد نوع للمتغير <code>nameEl</code>، لذا اضبط نوعه على النوع <code>HTMLElement</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_72" style=""><span class="kwd">let</span><span class="pln"> nameEl</span><span class="pun">:</span><span class="pln"> </span><span class="typ">HTMLElement</span><span class="pun">;</span><span class="pln"> </span><span class="com">// reference to the name input DOM node</span></pre>

<p>
	كما يجب تحديد النوع الصحيح للمتغير <code>autofocus</code>، لذا عدّل تعريفه إلى ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_75" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> autofocus</span><span class="pun">:</span><span class="pln"> boolean </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span></pre>

<h3>
	المكون Todo.svelte
</h3>

<p>
	تظهر التحذيرات الوحيدة التي يصدرها الأمر <code>npm run check</code> من خلال استدعاء المكوِّن <code>Todo.svelte</code>، إذًا لنصلحها.
</p>

<p>
	افتح الملف <code>Todo.svelte</code> وأضِف السمة <code>lang='ts'‎</code> ثم استورد النوع <code>TodoType</code> واضبط نوع الخاصية <code>todo</code>، أي استبدل السطر <code>export let todo</code> بما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_77" style=""><span class="kwd">import</span><span class="pln"> type </span><span class="pun">{</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../types/todo.type"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> todo</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">;</span></pre>

<p>
	التحذير الأول الذي حصلنا عليه هو أنّ لغة TypeScript تُعلِمنا بأنه يجب تحديد نوع المتغير <code>updatedTodo</code> الخاص بالدالة <code>update()‎</code>، كما يمكن أن يكون هذا صعبًا بعض الشيء لأن المتغير <code>updatedTodo</code> يحتوي فقط على سمات المهمة <code>todo</code> التي جرى تحديثها، وهذا يعني أنها ليست مهمة <code>todo</code> كاملة، فهي تحتوي فقط على مجموعة فرعية من خاصيات المهام، لذلك توفر لغة TypeScript العديد من الأدوات المساعدة الخاصة بالأنواع لتسهيل تطبيق هذه التحويلات الشائعة، حيث سنستخدِم الآن الأداة المساعدة <code>Partial&lt;T&gt;‎</code> التي تتيح تمثيل جميع المجموعات الفرعية من نوع معيّن، وتعيد نوعًا جديدًا بناءً على النوع <code>T</code>، إذ تكون كل خاصية من خصائص <code>T</code> اختياريةً، كما سنستخدِم هذه الأداة في الدالة <code>update()‎</code>، لذلك عدّلها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_79" style=""><span class="kwd">function</span><span class="pln"> update</span><span class="pun">(</span><span class="pln">updatedTodo</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Partial</span><span class="pun">&lt;</span><span class="typ">TodoType</span><span class="pun">&gt;)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">todo</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">updatedTodo </span><span class="pun">};</span><span class="pln"> </span><span class="com">// تطبيق التعديلات على المهمة</span><span class="pln">
  dispatch</span><span class="pun">(</span><span class="str">"update"</span><span class="pun">,</span><span class="pln"> todo</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إصدار حدث التحديث</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بذلك نخبر لغة TypeScript أنّ المتغير <code>updatedTodo</code> سيحتوي على مجموعة فرعية من الخاصيات ذات النوع <code>TodoType</code>.
</p>

<p>
	تخبرنا الآن الأداة svelte-check أنه يجب تعريف نوع معامِلات دالة الإجراء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_81" style=""><span class="pun">.</span><span class="str">/07-next-steps/</span><span class="pln">src</span><span class="pun">/</span><span class="pln">components</span><span class="pun">/</span><span class="typ">Todo</span><span class="pun">.</span><span class="pln">svelte</span><span class="pun">:</span><span class="lit">45</span><span class="pun">:</span><span class="lit">24</span><span class="pln">
</span><span class="typ">Warn</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Parameter</span><span class="pln"> </span><span class="str">'node'</span><span class="pln"> implicitly has an </span><span class="str">'any'</span><span class="pln"> type</span><span class="pun">,</span><span class="pln"> but a better type may be inferred from usage</span><span class="pun">.</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ts</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> focusOnInit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">node</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> node </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">focus </span><span class="pun">===</span><span class="pln"> </span><span class="str">'function'</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">()</span><span class="pln">

</span><span class="pun">./</span><span class="lit">07</span><span class="pun">-</span><span class="pln">next</span><span class="pun">-</span><span class="pln">steps</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="pln">components</span><span class="pun">/</span><span class="typ">Todo</span><span class="pun">.</span><span class="pln">svelte</span><span class="pun">:</span><span class="lit">47</span><span class="pun">:</span><span class="lit">28</span><span class="pln">
</span><span class="typ">Warn</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Parameter</span><span class="pln"> </span><span class="str">'node'</span><span class="pln"> implicitly has an </span><span class="str">'any'</span><span class="pln"> type</span><span class="pun">,</span><span class="pln"> but a better type may be inferred from usage</span><span class="pun">.</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ts</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> focusEditButton </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">node</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> editButtonPressed </span><span class="pun">&amp;&amp;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">()</span></pre>

<p>
	يجب فقط تعريف المعامل <code>node</code> ليكون من النوع <code>HTMLElement</code>، لذا استبدل النسخة الأولى من المعامِل <code>node</code> بالشكل <code>node: HTMLElement</code> في السطرين السابقين المشار إليهما.
</p>

<h3>
	الملف actions.js
</h3>

<p>
	أعد تسمية الملف actions.js إلى actions.ts وأضِف نوع المعامِل <code>node</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_83" style=""><span class="com">// actions.ts</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> selectOnFocus</span><span class="pun">(</span><span class="pln">node</span><span class="pun">:</span><span class="pln"> </span><span class="typ">HTMLInputElement</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">node </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">select </span><span class="pun">===</span><span class="pln"> </span><span class="str">"function"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ‫تأكد من أن المعامل node مُعرَّف ولديه التابع select()‎</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> onFocus </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">select</span><span class="pun">();</span><span class="pln"> </span><span class="com">// معالج الحدث</span><span class="pln">
    node</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"focus"</span><span class="pun">,</span><span class="pln"> onFocus</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫استدعِ التابع onFocus()‎ عند انتقال التركيز إلى العقدة node</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      destroy</span><span class="pun">:</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">removeEventListener</span><span class="pun">(</span><span class="str">"focus"</span><span class="pun">,</span><span class="pln"> onFocus</span><span class="pun">),</span><span class="pln"> </span><span class="com">// ‫سيُنفَّذ هذا عند حذف العقدة node في نموذج DOM</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عدّل الآن الملفين Todo.svelte و NewTodo.svelte حيث نستورد ملف الإجراءات actions، وتذكّر أن تعليمات الاستيراد في لغة TypeScript لا تتضمن امتداد الملف.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_85" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> selectOnFocus </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../actions"</span><span class="pun">;</span></pre>

<h3>
	ترحيل المخازن Stores إلى لغة TypeScript
</h3>

<p>
	يجب الآن ترحيل الملفين stores.js و localStore.js إلى لغة TypeScript.
</p>

<p>
	سيتحقق السكربت <code>npm run check</code> الذي يستخدِم الأداة <code>svelte-check</code> من ملفات <code>‎.svelte</code> الخاصة بتطبيقنا، فإذا أردتَ التحقق من ملفات <code>‎.ts</code>، فيمكنك تشغيل الأمر <code>npm run check &amp;&amp; npx tsc --noemit</code> الذي يخبر مصرِّف TypeScript بالتحقق من الأخطاء دون إنشاء ملفات الخرج <code>‎.js</code>، كما يمكنك إضافة سكربت إلى الملف package.json الذي يشغّل ذلك الأمر.
</p>

<p>
	سنبدأ بترحيل الملف stores.js:
</p>

<p>
	أعِد تسمية الملف إلى stores.ts ثم اضبط نوع المصفوفة <code>initialTodos</code> إلى النوع <code>TodoType[]‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_87" style=""><span class="com">// stores.ts</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> writable </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"svelte/store"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> localStore </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"./localStore.js"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> type </span><span class="pun">{</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"./types/todo.type"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> alert </span><span class="pun">=</span><span class="pln"> writable</span><span class="pun">(</span><span class="str">"Welcome to the To-Do list app!"</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> initialTodos</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Visit MDN web docs"</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Complete the Svelte Tutorial"</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> todos </span><span class="pun">=</span><span class="pln"> localStore</span><span class="pun">(</span><span class="str">"mdn-svelte-todo"</span><span class="pun">,</span><span class="pln"> initialTodos</span><span class="pun">);</span></pre>

<p>
	تذكّر تحديث تعليمات الاستيراد في الملفات App.svelte و Alert.svelte وTodos.svelte، وأزِل فقط الامتداد <code>‎.js</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_89" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> todos </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../stores"</span><span class="pun">;</span></pre>

<p>
	لننتقل الآن إلى الملف localStore.js، وعدّل تعليمة الاستيراد في الملف stores.ts كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_91" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> localStore </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"./localStore"</span><span class="pun">;</span></pre>

<p>
	أعِد تسمية الملف إلى localStore.ts، حيث تخبرنا لغة TypeScript بأنه يجب تحديد نوع المتغيرات <code>key</code> و <code>initial</code> و <code>value</code>، إذ يجب أن يكون المتغير الأول -وهو مفتاح تخزين الويب المحلي- سلسلةً نصيةً، لكن يجب أن يكون المتغيران <code>initial</code> و <code>value</code> أيّ كائن يمكن تحويله إلى سلسلة <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel="">JSON </a>صالحة باستخدام التابع <code>JSON.stringify</code>، مما يعني أن أيّ كائن جافاسكربت له قيود معينة مثل <code>undefined</code> والدوال والرموز التي ليست قيم JSON صالحة، لذا سننشئ النوع <code>JsonValue</code> لتحديد هذه الشروط. أنشئ الملف json.type.ts في المجلد <code>types</code> وضع فيه المحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_93" style=""><span class="kwd">export</span><span class="pln"> type </span><span class="typ">JsonValue</span><span class="pln"> </span><span class="pun">=</span><span class="pln">
  </span><span class="pun">|</span><span class="pln"> string
  </span><span class="pun">|</span><span class="pln"> number
  </span><span class="pun">|</span><span class="pln"> boolean
  </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">JsonValue</span><span class="pun">[]</span><span class="pln">
  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">]:</span><span class="pln"> </span><span class="typ">JsonValue</span><span class="pln"> </span><span class="pun">};</span></pre>

<p>
	يتيح المعامِل <code>|</code> التصريح عن المتغيرات التي يمكنها تخزين قيم من نوعين أو أكثر، كما يمكن أن يكون النوع <code>JsonValue</code> سلسلةً نصيةً أو عددًا أو قيمةً منطقيةً وما إلى ذلك، كما نستخدِم في هذه الحالة الأنواع العودية لتحديد أنّ النوع <code>JsonValue</code> يمكن أن يحتوي على مصفوفة من القيم ذات النوع <code>JsonValue</code> وكائن له خاصيات من النوع <code>JsonValue</code>.
</p>

<p>
	سنستورد النوع <code>JsonValue</code> وسنستخدِمه وفقًا لذلك، لذا عدّل الملف localStore.ts كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_97" style=""><span class="com">// localStore.ts</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> writable </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"svelte/store"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> type </span><span class="pun">{</span><span class="pln"> </span><span class="typ">JsonValue</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"./types/json.type"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> localStore </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">,</span><span class="pln"> initial</span><span class="pun">:</span><span class="pln"> </span><span class="typ">JsonValue</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// يتلقى مفتاح التخزين المحلي وقيمة أولية</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> toString </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">:</span><span class="pln"> </span><span class="typ">JsonValue</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln"> </span><span class="com">// دالة مساعدة</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> toObj </span><span class="pun">=</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">parse</span><span class="pun">;</span><span class="pln"> </span><span class="com">// دالة مساعدة</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">getItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">)</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// العنصر غير موجود في التخزين المحلي</span><span class="pln">
    localStorage</span><span class="pun">.</span><span class="pln">setItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> toString</span><span class="pun">(</span><span class="pln">initial</span><span class="pun">));</span><span class="pln"> </span><span class="com">// تهيئة التخزين المحلي بالقيمة الأولية</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> saved </span><span class="pun">=</span><span class="pln"> toObj</span><span class="pun">(</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">getItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">));</span><span class="pln"> </span><span class="com">// تحويل إلى كائن</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> subscribe</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">,</span><span class="pln"> update </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> writable</span><span class="pun">(</span><span class="pln">saved</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إنشاء المتجر الأساسي القابل للكتابة</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    subscribe</span><span class="pun">,</span><span class="pln">
    </span><span class="kwd">set</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">:</span><span class="pln"> </span><span class="typ">JsonValue</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      localStorage</span><span class="pun">.</span><span class="pln">setItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> toString</span><span class="pun">(</span><span class="pln">value</span><span class="pun">));</span><span class="pln"> </span><span class="com">// حفظ القيمة في التخزين المحلي كسلسلة نصية</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    update</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	إذا حاولنا الآن إنشاء مخزن <code>localStore</code> مع شيء لا يمكن تحويله إلى صيغة JSON باستخدام التابع <code>JSON.stringify()‎</code> مثل كائن مع دالة بوصفها خاصيةً له، فسيعطي المحرر VS Code أو <code>validate</code> خطأً كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117053" href="https://academy.hsoub.com/uploads/monthly_2023_01/11-vscode-invalid-store.png.58ffd4f8248d0139439b82a77135ac87.png" rel=""><img alt="نتيجة إنشاء مخزن localStore مع شيء لا يمكن تحويله إلى صيغة JSON " class="ipsImage ipsImage_thumbnailed" data-fileid="117053" data-ratio="17.95" data-unique="5nu8euvub" style="width: 780px; height: auto;" width="780" src="https://academy.hsoub.com/uploads/monthly_2023_01/11-vscode-invalid-store.thumb.png.65db4ecffa86751af459f6d2edc54922.png"> </a>
</p>

<p>
	سيعمل الملف localStore.ts مع صيغة الاشتراك التلقائي <code>‎$store</code>، فإذا حاولنا حفظ قيمة غير صالحة في مخزن <code>todos</code> باستخدام صيغة <code>‎$store</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_100" style=""><span class="pun">&lt;!--</span><span class="pln"> </span><span class="typ">App</span><span class="pun">.</span><span class="pln">svelte </span><span class="pun">--&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">script lang</span><span class="pun">=</span><span class="str">"ts"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Todos</span><span class="pln"> from </span><span class="str">"./components/Todos.svelte"</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Alert</span><span class="pln"> from </span><span class="str">"./components/Alert.svelte"</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> todos </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"./stores"</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// ‫هذه قيمة غير صالحة، فالمحتوى لا يمكن تحويله إلى صيغة JSON باستخدام JSON.stringify</span><span class="pln">
  $todos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> handler</span><span class="pun">:</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{}</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	فسيعطي سكربت التحقق الخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_102" style=""><span class="pun">&gt;</span><span class="pln"> npm run check

</span><span class="typ">Getting</span><span class="pln"> </span><span class="typ">Svelte</span><span class="pln"> diagnostics</span><span class="pun">...</span><span class="pln">
</span><span class="pun">====================================</span><span class="pln">

</span><span class="pun">./</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">typescript</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="typ">App</span><span class="pun">.</span><span class="pln">svelte</span><span class="pun">:</span><span class="lit">8</span><span class="pun">:</span><span class="lit">12</span><span class="pln">
</span><span class="typ">Error</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Argument</span><span class="pln"> </span><span class="kwd">of</span><span class="pln"> type </span><span class="str">'{ handler: () =&gt; void; }'</span><span class="pln"> is not assignable to parameter </span><span class="kwd">of</span><span class="pln"> type </span><span class="str">'JsonValue'</span><span class="pun">.</span><span class="pln">
  </span><span class="typ">Types</span><span class="pln"> </span><span class="kwd">of</span><span class="pln"> property </span><span class="str">'handler'</span><span class="pln"> are incompatible</span><span class="pun">.</span><span class="pln">
    </span><span class="typ">Type</span><span class="pln"> </span><span class="str">'() =&gt; void'</span><span class="pln"> is not assignable to type </span><span class="str">'JsonValue'</span><span class="pun">.</span><span class="pln">
      </span><span class="typ">Type</span><span class="pln"> </span><span class="str">'() =&gt; void'</span><span class="pln"> is not assignable to type </span><span class="str">'{ [key: string]: JsonValue; }'</span><span class="pun">.</span><span class="pln">
        </span><span class="typ">Index</span><span class="pln"> signature is missing in type </span><span class="str">'() =&gt; void'</span><span class="pun">.</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ts</span><span class="pun">)</span><span class="pln">
 $todos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> handler</span><span class="pun">:</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{}</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	يُعَدّ ذلك مثالًا آخر على كيفية تحديد الأنواع الذي يمكن أن يجعل شيفرتنا أقوى ويساعدنا في اكتشاف مزيد من الأخطاء قبل دخولها في عملية الإنتاج.
</p>

<p>
	حوّلنا بذلك تطبيقنا بالكامل ليستخدِم لغة TypeScript.
</p>

<h2>
	حماية المخازن من الأخطاء باستخدام الأنواع المعممة
</h2>

<p>
	نقلنا المخازن إلى لغة TypeScript، ولكن يمكننا تنفيذ عمل أفضل، فلا يجب علينا تخزين أيّ نوع من القيم، لأننا نعلم أنّ مخزن التنبيه <code>alert</code> يجب أن يحتوي على رسائل نصية، كما يجب أن يحتوي متجر المهام <code>todos</code> على مصفوفة من النوع <code>TodoType</code> وما إلى ذلك، ويمكننا السماح للغة TypeScript بفرض ذلك باستخدام الأنواع المُعمَّمة Generics في لغة TypeScript.
</p>

<h3>
	الأنواع المعممة Generics في لغة TypeScript
</h3>

<p>
	تسمح <a href="https://wiki.hsoub.com/TypeScript/generics" rel="external">الأنواع المُعمَّمة</a> بإنشاء مكونات برمجية قابلة لإعادة الاستخدام تعمل مع مجموعة متنوعة من الأنواع بدلًا من نوع واحد، ويمكن تطبيقها على الواجهات والأصناف والدوال.
</p>

<p>
	تُمرَّر الأنواع المُعمَّمة بوصفها معامِلات باستخدام صيغة خاصة، إذ تُحدَّد بين قوسَي زاوية، ويُشار إليها حسب الاصطلاح بحرف واحد كبير، كما تسمح الأنواع المُعمَّمة بالتقاط الأنواع التي يوفرها المستخدِم لاستخدامها لاحقًا، ولنرى مثالًا سريعًا يمثل الصنف <code>Stack</code> البسيط الذي يتيح دفع <code>push</code> العناصر وسحبها <code>pop</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_104" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Stack</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">private</span><span class="pln"> elements </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">

  push </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">element</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">elements</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">element</span><span class="pun">)</span><span class="pln">

  pop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">elements</span><span class="pun">.</span><span class="pln">length </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'The stack is empty!'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">elements</span><span class="pun">.</span><span class="pln">pop</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تكون <code>elements</code> في هذه الحالة مصفوفةً من النوع <code>any</code>، وبالتالي يستقبل ويعيد التابعان <code>push()‎</code> و <code>pop()‎</code> متغيرًا من النوع <code>any</code>، لذا يمكنك تطبيق ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_106" style=""><span class="kwd">const</span><span class="pln"> anyStack </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Stack</span><span class="pun">();</span><span class="pln">

anyStack</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
anyStack</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span></pre>

<p>
	لكن إذا أردنا الحصول على الصنف <code>Stack</code> الذي يعمل فقط مع نوع السلسلة النصية <code>string</code>، فيمكننا تطبيق ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_108" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">StringStack</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">private</span><span class="pln"> elements</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">

  push </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">elements</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">element</span><span class="pun">)</span><span class="pln">

  pop</span><span class="pun">():</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">elements</span><span class="pun">.</span><span class="pln">length </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'The stack is empty!'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">elements</span><span class="pun">.</span><span class="pln">pop</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أما إذا أردنا التعامل مع الأعداد، فسنضطر بعد ذلك إلى تكرار الشيفرة وإنشاء الصنف <code>NumberStack</code>، وإذا أردنا التعامل مع مجموعة من الأنواع التي لا نعرفها بعد ويجب أن يعرّفها المستخدِم، فيمكننا استخدام الأنواع المُعمَّمة Generics.
</p>

<p>
	إليك الصنف <code>Stack</code> الذي أعيد تطبيقه باستخدام الأنواع المُعمَّمة Generics:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_110" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Stack</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">private</span><span class="pln"> elements</span><span class="pun">:</span><span class="pln"> T</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">

  push </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> T</span><span class="pun">):</span><span class="pln"> number </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">elements</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">element</span><span class="pun">)</span><span class="pln">

  pop</span><span class="pun">():</span><span class="pln"> T </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">elements</span><span class="pun">.</span><span class="pln">length </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'The stack is empty!'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">elements</span><span class="pun">.</span><span class="pln">pop</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نعرِّف النوع <code>T</code> المُعمَّم ثم نستخدِمه كما نستخدِم أيّ نوع آخر، إذ تُعَدّ <code>elements</code> الآن مصفوفةً من النوع <code>T</code>، كما يستقبل ويعيد كل من التابعين <code>push()‎</code> و <code>pop()‎</code> متغيرًا من النوع <code>T</code>.
</p>

<p>
	إليك الطريقة التي نستخدِم بها النوع المُعمَّم <code>Stack</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_112" style=""><span class="kwd">const</span><span class="pln"> numberStack </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Stack</span><span class="pun">&lt;</span><span class="pln">number</span><span class="pun">&gt;()</span><span class="pln">
numberStack</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span></pre>

<p>
	تعرف لغة TypeScript الآن أنّ <code>Stack</code> يمكنه قبول الأعداد فقط وسيعطي خطأً إذا حاولنا دفع أيّ شيء آخر:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117054" href="https://academy.hsoub.com/uploads/monthly_2023_01/12-vscode-generic-stack-error.png.c0146c32e6a9f570acbb1dd03723e3b7.png" rel=""><img alt=" قبول Stack للأعداد فقط" class="ipsImage ipsImage_thumbnailed" data-fileid="117054" data-ratio="27.31" data-unique="84pjiwgdq" style="width: 780px; height: auto;" width="780" src="https://academy.hsoub.com/uploads/monthly_2023_01/12-vscode-generic-stack-error.png.c0146c32e6a9f570acbb1dd03723e3b7.png"> </a>
</p>

<p>
	كما يمكن للغة TypeScript استنتاج الأنواع المُعمَّمة من خلال استخدامها، إذ تدعم القيم الافتراضية والقيود، كما تُعَدّ الأنواع المُعمَّمة ميزةً قويةً تسمح للشيفرة البرمجية بتجريد الأنواع المُحدَّدة المُستخدَمة، مما يجعلها أكثر قابليةً لإعادة الاستخدام ومُعمَّمة دون التخلي عن أمان الأنواع.
</p>

<h3>
	استخدام مخازن Svelte مع الأنواع المعممة
</h3>

<p>
	تدعم مخازن Svelte الأنواع المُعمَّمة، إذ يمكننا الاستفادة من ميزة استنتاج الأنواع المُعمَّمة دون لمس شيفرتنا البرمجية، فإذا فتحت الملف Todos.svelte وأسندتَ النوع <code>number</code> إلى المخزن <code>‎$alert</code>، فستحصل على الخطأ التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117055" href="https://academy.hsoub.com/uploads/monthly_2023_01/13-vscode-generic-alert-error.png.177226d1b69eb75f1c2595d9cd654f86.png" rel=""><img alt="استخدام مخازن Svelte مع الأنواع المعممة" class="ipsImage ipsImage_thumbnailed" data-fileid="117055" data-ratio="25.13" data-unique="ci6ttyj2v" style="width: 780px; height: auto;" width="780" src="https://academy.hsoub.com/uploads/monthly_2023_01/13-vscode-generic-alert-error.png.177226d1b69eb75f1c2595d9cd654f86.png"> </a>
</p>

<p>
	لأنه عندما عرّفنا المخزن <code>alert</code> في الملف stores.ts باستخدام ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_116" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> alert </span><span class="pun">=</span><span class="pln"> writable</span><span class="pun">(</span><span class="str">"Welcome to the To-Do list app!"</span><span class="pun">);</span></pre>

<p>
	استنتجت لغة TypeScript أنّ النوع المُعمَّم هو سلسلة نصية <code>string</code>، فإذا أردنا أن نكون صريحين بشأن ذلك، فيمكننا كتابة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_118" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> alert </span><span class="pun">=</span><span class="pln"> writable </span><span class="pun">&lt;</span><span class="pln"> string </span><span class="pun">&gt;</span><span class="pln"> </span><span class="str">"Welcome to the To-Do list app!"</span><span class="pun">;</span></pre>

<p>
	سنجعل الآن المخزن <code>localStore</code> يدعم الأنواع المُعمَّمة، وتذكّر أننا عرّفنا النوع <code>JsonValue</code> لمنع استخدام المخزن <code>localStore</code> مع قيم لا يمكن استمرارها باستخدام التابع <code>JSON.stringify()‎</code>.
</p>

<p>
	نريد الآن أن يتمكن مستخدِمو المخزن <code>localStore</code> من تحديد نوع البيانات المستمرة، ولكن يجب استخدام النوع <code>JsonValue</code> بدلًا من العمل مع أيّ نوع، لذا سنحدد ذلك بقيد مُعمَّم كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_120" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> localStore </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">T extends </span><span class="typ">JsonValue</span><span class="pun">&gt;(</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">,</span><span class="pln"> initial</span><span class="pun">:</span><span class="pln"> T</span><span class="pun">)</span></pre>

<p>
	سنعرّف النوع المُعمَّم <code>T</code> وسنحدِّد أنه يجب أن يكون متوافقًا مع النوع <code>JsonValue</code>، ثم سنستخدِم النوع <code>T</code> بطريقة مناسبة، وسيكون الملف localStore.ts كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_123" style=""><span class="com">// localStore.ts</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> writable </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte/store'</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> type </span><span class="pun">{</span><span class="pln"> </span><span class="typ">JsonValue</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./types/json.type'</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> localStore </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">T extends </span><span class="typ">JsonValue</span><span class="pun">&gt;(</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">,</span><span class="pln"> initial</span><span class="pun">:</span><span class="pln"> T</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">          </span><span class="com">// يتلقى مفتاح التخزين المحلي وقيمة أولية</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> toString </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">:</span><span class="pln"> T</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">           </span><span class="com">// دالة مساعدة</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> toObj </span><span class="pun">=</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">parse                                                </span><span class="com">// دالة مساعدة</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">getItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">)</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                               </span><span class="com">// العنصر غير موجود في التخزين المحلي</span><span class="pln">
    localStorage</span><span class="pun">.</span><span class="pln">setItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> toString</span><span class="pun">(</span><span class="pln">initial</span><span class="pun">))</span><span class="pln">                          </span><span class="com">// تهيئة التخزين المحلي بالقيمة الأولية</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> saved </span><span class="pun">=</span><span class="pln"> toObj</span><span class="pun">(</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">getItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">))</span><span class="pln">                          </span><span class="com">// تحويل إلى كائن</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> subscribe</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">,</span><span class="pln"> update </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> writable</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;(</span><span class="pln">saved</span><span class="pun">)</span><span class="pln">                   </span><span class="com">// إنشاء المتجر الأساسي القابل للكتابة</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    subscribe</span><span class="pun">,</span><span class="pln">
    </span><span class="kwd">set</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">:</span><span class="pln"> T</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      localStorage</span><span class="pun">.</span><span class="pln">setItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> toString</span><span class="pun">(</span><span class="pln">value</span><span class="pun">))</span><span class="pln">                          </span><span class="com">// حفظ القيمة في التخزين المحلي كسلسلة نصية</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    update
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تعرف لغة TypeScript أن المخزن <code>‎$todos</code> يجب أن يحتوي على مصفوفة من النوع <code>TodoType</code> بفضل ميزة استنتاج الأنواع المُعمَّمة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="117056" href="https://academy.hsoub.com/uploads/monthly_2023_01/14-vscode-generic-localstore-error.png.971785adcf8dd411ade227a4f2963e52.png" rel=""><img alt="المخزن ‎$todos يجب أن يحتوي على مصفوفة من النوع TodoType" class="ipsImage ipsImage_thumbnailed" data-fileid="117056" data-ratio="10.38" data-unique="exwz00iml" style="width: 780px; height: auto;" width="780" src="https://academy.hsoub.com/uploads/monthly_2023_01/14-vscode-generic-localstore-error.thumb.png.788fcde99ce30e78ed3f433d7952bf9f.png"> </a>
</p>

<p>
	كما ذكرنا سابقًا إذا أردنا أن نكون صريحين، فيمكننا ذلك في الملف stores.ts كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_126" style=""><span class="kwd">const</span><span class="pln"> initialTodos</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TodoType</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Visit MDN web docs'</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Complete the Svelte Tutorial'</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
</span><span class="pun">]</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> todos </span><span class="pun">=</span><span class="pln"> localStore</span><span class="pun">&lt;</span><span class="typ">TodoType</span><span class="pun">[]&gt;(</span><span class="str">'mdn-svelte-todo'</span><span class="pun">,</span><span class="pln"> initialTodos</span><span class="pun">)</span></pre>

<p>
	يمكنك الوصول إلى نسختك من مستودعنا على النحو التالي لمعرفة حالة الشيفرة كما يجب أن تكون في نهاية هذا المقال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_128" style=""><span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">08</span><span class="pun">-</span><span class="pln">next</span><span class="pun">-</span><span class="pln">steps</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9012_130" style=""><span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">08</span><span class="pun">-</span><span class="pln">next</span><span class="pun">-</span><span class="pln">steps</span></pre>

<p>
	تذكَّر تشغيل الأمر <code>npm install &amp;&amp; npm run dev</code> لبدء تشغيل تطبيقك في وضع التطوير.
</p>

<p>
	<strong>ملاحظة</strong>: كما قلنا سابقًا لا يتوفر دعم لغة TypeScript في أداة REPL حتى الآن لسوء الحظ.
</p>

<h2>
	الخلاصة
</h2>

<p>
	نقلنا تطبيق قائمة المهام إلى لغة TypeScript في هذا المقال، إذ تعرّفنا أولًا على لغة TypeScript ومزاياها، ثم رأينا كيفية إنشاء مشروع Svelte جديد مع دعم TypeScript، وكيفية تحويل مشروع Svelte قائم هو تطبيق قائمة المهام لاستخدام لغة TypeScript.
</p>

<p>
	رأينا كيفية العمل مع المحرّر Visual Studio Code والإضافة Svelte للحصول على ميزات مثل التحقق من الأنواع والإكمال التلقائي، واستخدمنا الأداة <code>svelte-check</code> لفحص مشاكل TypeScript من سطر الأوامر، كما سنتعلّم في المقال التالي كيفية تصريف ونشر تطبيقنا للإنتاج، وسنرى موارد التعلم المتاحة عبر الإنترنت للمضي قدمًا في تعلم إطار عمل Svelte.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_TypeScript" rel="external nofollow">TypeScript support in Svelte</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">بدء استخدام إطار العمل Svelte لبناء تطبيقات ويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/typescript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-typescript-r1214/" rel="">مدخل إلى TypeScript</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/typescript/%D8%A7%D9%84%D8%AE%D8%B7%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%89-%D9%81%D9%8A-%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-typescript-r1215/" rel="">الخطوات الأولى في بناء تطبيقات الويب باستعمال TypeScript</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1811/" rel="">إنشاء تطبيق قائمة مهام باستعمال إطار عمل Svelte</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1871</guid><pubDate>Sat, 04 Feb 2023 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x645;&#x62E;&#x627;&#x632;&#x646; Stores &#x641;&#x64A; &#x625;&#x637;&#x627;&#x631; &#x639;&#x645;&#x644; Svelte</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AE%D8%A7%D8%B2%D9%86-stores-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1864/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/905361182_--Stores----Svelte.png.983dd193ab05b4621adf9048ff540f05.png" /></p>
<p>
	أكملنا في مقال <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D9%81%D8%A7%D8%B9%D9%84%D9%8A%D8%A9-%D9%88%D8%AF%D9%88%D8%B1%D8%A9-%D8%A7%D9%84%D8%AD%D9%8A%D8%A7%D8%A9-%D9%88%D8%B3%D9%87%D9%88%D9%84%D8%A9-%D9%88%D8%B5%D9%88%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%8A%D9%86-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1863/" rel="">التفاعلية ودورة الحياة وسهولة وصول المستخدمين</a> تطوير تطبيقنا وانتهينا من تنظيمه في مكونات، كما ناقشنا بعض التقنيات المتقدمة للتعامل مع التفاعلية والعمل مع عُقد DOM والوصول إلى وظائف المكونات، وسنعرض في هذا المقال طريقةً أخرى للتعامل مع إدارة الحالة في إطار عمل Svelte وهي المخازن Stores والتي تُعَدّ مستودعات بيانات عامة تحتفظ بالقيم، ويمكن للمكونات الاشتراك بالمخازن وتلقّي إشعارات عندما تتغير قيمها.
</p>

<ul>
	<li>
		<strong>المتطلبات الأساسية</strong>: يوصَى على الأقل بأن تكون على دراية بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة باستخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471" rel="">سطر الأوامر أو الطرفية</a>، كما ستحتاج طرفية مثبَّت عليها node و npm لتصريف وبناء تطبيقك.
	</li>
	<li>
		<strong>الهدف</strong>: تعلّم كيفية استخدام المخازن Stores في <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">إطار عمل Svelte</a>.
	</li>
</ul>

<p>
	سننشئ المكوِّن <code>Alert</code> الذي يعرض إشعارات على الشاشة باستخدام المخازن، ويمكنه استقبال الرسائل من جميع المكونات الأخرى، إذ يكون المكوِّن <code>Alert</code> في هذه الحالة مستقلًا عن المكونات الأخرى، فهو ليس أبًا أو ابنًا لأيّ مكوِّن آخر، لذلك لا تتناسب الرسائل مع تسلسل المكونات الهرمي، كما سنرى كيفية تطوير المخزن المخصَّص للاحتفاظ بمعلومات المهام في تخزين الويب، مما يسمح لمهامنا بالاستمرار خلال في صفحات التحميل.
</p>

<p>
	يمكن متابعة كتابة شيفرتك معنا، لذلك انسخ أولًا مستودع github -إذا لم تفعل ذلك مسبقًا- باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_10" style=""><span class="pln">git clone https</span><span class="pun">:</span><span class="com">//github.com/opensas/mdn-svelte-tutorial.git</span></pre>

<p>
	ثم يمكنك الوصول إلى حالة التطبيق الحالية من خلال تشغيل الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_12" style=""><span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">06</span><span class="pun">-</span><span class="pln">stores</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_14" style=""><span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">06</span><span class="pun">-</span><span class="pln">stores</span></pre>

<p>
	تذكَّر تشغيل الأمر <code>npm install &amp;&amp; npm run dev</code> لبدء تشغيل تطبيقك في وضع التطوير، فإذا أردت متابعتنا، فابدأ بكتابة الشيفرة باستخدام الأداة REPL من <a href="https://svelte.dev/repl/d1fa84a5a4494366b179c87395940039?version=3.23.2" rel="external nofollow">svelte.dev</a>.
</p>

<h2>
	التعامل مع حالة تطبيقنا
</h2>

<p>
	رأينا مسبقًا كيف يمكن لمكوناتنا التواصل مع بعضها البعض باستخدام الخاصيات وربط البيانات ثنائي الاتجاه والأحداث، إذ تعاملنا في كل هذه الحالات مع التواصل بين المكونات الآباء والمكونات الأبناء، لكن لا تنتمي جميع حالات التطبيق إلى تسلسل مكونات التطبيق الهرمي مثل معلومات المستخدِم الذي سجّل الدخول أو ما إذا كان القالب الداكن محددًا أم لا، إذ ستحتاج حالة التطبيق في بعض الأحيان إلى الوصول إليها من خلال عدة مكونات غير مرتبطة بالتسلسل الهرمي أو عن طريق وحدة JavaScript عادية.
</p>

<p>
	كما يمكن أن يصبح ترحيل البيانات بين المكونات صعبًا جدًا عندما يكون تطبيقك وتسلسل المكونات الهرمي معقّدَين، لذا يمكن أن يكون الانتقال إلى مخزن بيانات عام خيارًا جيدًا في هذه الحالة، فإذا استخدمت مسبقًا مكتبتَي Redux أو Vuex، فستكون على دراية بكيفية عمل هذا النوع من المخازن، إذ تقدّم مخازن Svelte ميزات مماثلة لإدارة الحالة.
</p>

<p>
	يُعَدّ المخزن Store كائنًا يمتلك التابع <code>subscribe()‎</code> الذي يسمح بإعلام الأطراف المهتمة كلما تغيرت قيمة هذا المخزن، والتابع الاختياري <code>set()‎</code> الذي يسمح بضبط قيم جديدة للمخزن، إذ يُعرَف الحد الأدنى من واجهة برمجة التطبيقات باسم عَقد المخزن Store Contract.
</p>

<p>
	يوفر إطار عمل Svelte دوالًا لإنشاء مخازن قابلة للقراءة والكتابة ومشتقة في وحدة <code>svelte/store</code>، كما يوفر طريقةً بسيطةً لدمج المخازن في نظام التفاعل باستخدام الصيغة التفاعلية <code>‎$store</code>، فإذا أنشأتَ مخازنك الخاصة مع التقيّد بعَقد المخزن، فستحصل على هذه الصيغة المُختصَرة التفاعلية مجانًا.
</p>

<h2>
	إنشاء المكون Alert
</h2>

<p>
	سننشئ المكوِّن <code>Alert</code> لتوضيح كيفية العمل مع المخازن، ويمكن أن تُعرَف هذه الأنواع من عناصر واجهة المستخدِم باسم الإشعارات المنبثقة أو الرسائل المؤقتة toast أو الإشعارات الفقاعية Notification Bubbles.
</p>

<p>
	سيعرض المكوِّنُ <code>App</code> المكوِّنَ <code>Alert</code>، ولكن يمكن لأيّ مكوِّن إرسال إشعارات إليه، حيث سيكون المكوِّن <code>Alert</code> مسؤولًا عن عرض الإشعار على الشاشة عند وصوله.
</p>

<h3>
	إنشاء مخزن
</h3>

<p>
	لنبدأ بإنشاء مخزن قابل للكتابة، إذ سيتمكن أيّ مكوِّن من الكتابة في هذا المخزن وسيشترك المكوِّن <code>Alert</code> فيه ويعرض رسالةً كلما جرى تعديل المخزن.
</p>

<p>
	أولًا، أنشئ ملفًا جديدًا بالاسم <code>stores.js</code> ضمن المجلد <code>src</code>.
</p>

<p>
	ثانيًا، أضِف إليه المحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_17" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> writable </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte/store'</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> alert </span><span class="pun">=</span><span class="pln"> writable</span><span class="pun">(</span><span class="str">'Welcome to the to-do list app!'</span><span class="pun">)</span></pre>

<p>
	<strong>ملاحظة</strong>: يمكن تعريف المخازن واستخدامها خارج مكونات Svelte بحيث يمكنك تنظيمها بأيّ طريقة تريدها.
</p>

<p>
	استوردنا في الشيفرة السابقة الدالة <code>writable()‎</code> من الوحدة <code>svelte/store</code> واستخدمناها لإنشاء مخزن جديد يسمى <code>alert</code> مع قيمة أولية هي Welcome to the to-do list app!‎ ثم صدّرنا هذا المخزن.
</p>

<h3>
	إنشاء المكون الفعلي
</h3>

<p>
	لننشئ المكوِّن <code>Alert</code> ونرى كيف يمكننا قراءة القيم من المخزن.
</p>

<p>
	أولًا، أنشئ ملفًا جديدًا آخر بالاسم <code>src/components/Alert.svelte</code>.
</p>

<p>
	ثانيًا، ضع فيه المحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_985_19" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../stores.js'</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> onDestroy </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte'</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> alertContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> unsubscribe </span><span class="pun">=</span><span class="pln"> alert</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">(</span><span class="pln">value </span><span class="pun">=&gt;</span><span class="pln"> alertContent </span><span class="pun">=</span><span class="pln"> value</span><span class="pun">)</span><span class="pln">

  onDestroy</span><span class="pun">(</span><span class="pln">unsubscribe</span><span class="pun">)</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

{#if alertContent}
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> alertContent = ''}&gt;
  </span><span class="tag">&lt;p&gt;</span><span class="pln">{ alertContent }</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
{/if}

</span><span class="tag">&lt;style&gt;</span><span class="pln">
div </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">position</span><span class="pun">:</span><span class="pln"> fixed</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">margin-right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5rem</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">margin-left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5rem</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">margin-top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">align-items</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">border-radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.2rem</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">background-color</span><span class="pun">:</span><span class="pln"> </span><span class="lit">#565656</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">color</span><span class="pun">:</span><span class="pln"> </span><span class="lit">#fff</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">font-size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.875rem</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">font-weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">700</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.5rem</span><span class="pln"> </span><span class="lit">1.4rem</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">font-size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5rem</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">z-index</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">95%</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
div p </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">color</span><span class="pun">:</span><span class="pln"> </span><span class="lit">#fff</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
div svg </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.6rem</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">fill</span><span class="pun">:</span><span class="pln"> currentColor</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.4rem</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">margin-right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.5rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	لنتعرّف على تفاصيل الشيفرة البرمجية السابقة:
</p>

<ul>
	<li>
		نستورد أولًا المخزن <code>alert</code>.
	</li>
	<li>
		ثم نستورد دالة دورة الحياة <code>onDestroy()‎</code> التي تتيح تنفيذ دالة رد نداء بعد إلغاء تثبيت المكوِّن.
	</li>
	<li>
		ثم ننشئ متغيرًا محليًا بالاسم <code>alertContent</code>، وتذكّر أنه يمكننا الوصول إلى متغيرات المستوى الأعلى من شيفرة <a href="https://academy.hsoub.com/programming/html/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-html-r1687/" rel="">HTML</a>، وكلما عُدِّلت، سيُحدَّث <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">نموذج DOM </a>وفقًا لذلك.
	</li>
	<li>
		ثم نستدعي التابع <code>alert.subscribe()‎</code> ونمرِّر له دالة رد نداء بوصفها معاملًا، وكلما تغيرت قيمة المخزن، ستُستدعَى دالة رد النداء مع القيمة الجديدة بوصفها معاملًا لها، كما نسند القيمة التي نتلقاها إلى متغير محلي في دالة رد النداء، مما يؤدي إلى تحديث نموذج DOM الخاص بالمكوِّن.
	</li>
	<li>
		يعيد التابع <code>subscribe()‎</code> دالة التنظيف التي تتولى تحرير الاشتراك، وبذلك نشترك عند تهيئة المكوِّن ونستخدِم الدالة <code>onDestroy</code> لإلغاء الاشتراك عندما يكون المكوِّن غير مثبَّت.
	</li>
	<li>
		نستخدِم أخيرًا المتغير <code>alertContent</code> في شيفرة HTML، فإذا نقر المستخدِم على التنبيه، فسننظفه.
	</li>
	<li>
		نضمّن في النهاية عددًا من سطور <a href="https://academy.hsoub.com/programming/css/%d8%aa%d8%b9%d8%b1%d9%91%d9%81-%d8%b9%d9%84%d9%89-%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d8%a7%d8%aa-css-r70/" rel="">CSS</a> لتنسيق المكوِّن <code>Alert</code>.
	</li>
</ul>

<p>
	يتيح هذا الإعداد العمل مع المخازن بطريقة تفاعلية، فإذا تغيرت قيمة المخزن، فستُنفَّذ دالة رد النداء، ونسند قيمةً جديدةً لمتغير محلي، مما يؤدي إلى تحديث شيفرة HTML وجميع الاعتماديات التفاعلية وفقًا لذلك بفضل خاصية التفاعل في إطار عمل Svelte.
</p>

<h3>
	استخدام المكون
</h3>

<p>
	لنستخدِم الآن مكوننا الخاص.
</p>

<p>
	أولًا، سنستورد المكوِّن في الملف <code>App.svelte</code>، لذا أضِف تعليمة الاستيراد التالية بعد تعليمات الاستيراد الأخرى الموجودة مسبقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_24" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">Alert</span><span class="pln"> from </span><span class="str">'./components/Alert.svelte'</span></pre>

<p>
	ثم استدعِ المكوِّن <code>Alert</code> قبل استدعاء المكوِّن <code>Todos</code> مباشرةً كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_985_26" style=""><span class="tag">&lt;Alert</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
</span><span class="tag">&lt;Todos</span><span class="pln"> {</span><span class="atn">todos</span><span class="pln">} </span><span class="tag">/&gt;</span></pre>

<p>
	حمّل تطبيقك التجريبي الآن، وسترى الآن رسالة تنبيه <code>Alert</code> على الشاشة، إذ يمكنك النقر عليها لإبعادها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="116345" href="https://academy.hsoub.com/uploads/monthly_2023_01/01-alert-message.png.01b99bb9289fc16a7f7cadd9de7a5482.png" rel=""><img alt="رسالة تنبيه Alert على الشاشة في التطبيق التجريبي" class="ipsImage ipsImage_thumbnailed" data-fileid="116345" data-ratio="47.27" data-unique="ll1v1e1aj" style="width: 550px; height: 260px;" width="650" src="https://academy.hsoub.com/uploads/monthly_2023_01/01-alert-message.png.01b99bb9289fc16a7f7cadd9de7a5482.png"> </a>
</p>

<h2>
	جعل المخازن تفاعلية باستخدام الصيغة التفاعلية ‎$store
</h2>

<p>
	يمكن أن ينجح ذلك، ولكن يجب عليك نسخ الشيفرة التالية ولصقها في كل مرة تريد فيها الاشتراك في المخزن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_31" style=""><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> myStore from </span><span class="str">"./stores.js"</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> onDestroy </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"svelte"</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> myStoreContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> unsubscribe </span><span class="pun">=</span><span class="pln"> myStore</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">((</span><span class="pln">value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">myStoreContent </span><span class="pun">=</span><span class="pln"> value</span><span class="pun">));</span><span class="pln">

  onDestroy</span><span class="pun">(</span><span class="pln">unsubscribe</span><span class="pun">);</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">{</span><span class="pln">myStoreContent</span><span class="pun">}</span></pre>

<p>
	تُعَدّ الشيفرة البرمجية السابقة مكررةً بكثرة، وهذا كثير على إطار عمل Svelte، لأنه يمتلك مزيدًا من الموارد لتسهيل الأمور لكونه مصرِّفًا Compiler، كما يوفر إطار عمل Svelte الصيغة التفاعلية <code>‎$store</code> المعروفة باسم الاشتراك التلقائي، إذ ما عليك سوى إضافة العلامة <code>$</code> إلى المخزن، وسينشئ إطار Svelte الشيفرة البرمجية اللازمة لجعله تفاعليًا تلقائيًا، لذلك يمكن استبدال كتلة الشيفرة البرمجية السابقة بما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_985_35" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
 </span><span class="kwd">import</span><span class="pln"> myStore from </span><span class="str">"./stores.js"</span><span class="pun">;</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

{$myStore}</span></pre>

<p>
	سيكون المخزن <code>‎$myStore</code> تفاعليًا بصورة كاملة، وينطبق ذلك على مخازنك المخصَّصة، فإذا طبَّقتَ التابعَين <code>subscribe()‎</code> و <code>set()‎</code> كما سنفعل لاحقًا، فستُطبَّق الصيغة التفاعلية <code>‎$store</code> على مخازك أيضًا.
</p>

<p>
	لنطبّق ذلك على المكوِّن <code>Alert</code>، لذا عدّل القسمين <code>&lt;script&gt;</code> وشيفرة HTML في الملف<code> Alert.svelte </code>كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_985_37" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../stores.js'</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

{#if $alert}
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> $alert = ''}&gt;
  </span><span class="tag">&lt;p&gt;</span><span class="pln">{ $alert }</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
{/if}</span></pre>

<p>
	تحقق من تطبيقك مرةً أخرى، وسترى أنه يعمل بصورة أفضل.
</p>

<p>
	أنشأ إطار عمل Svelte في الخلفية شيفرةً برمجيةً للتصريح عن المتغير المحلي <code>‎$alert</code> وللاشتراك في المخزن <code>alert</code> ولتحديث <code>‎$alert</code> كلما جرى تعديل محتوى المخزن ولإلغاء الاشتراك عند إلغاء تثبيت المكوِّن، كما سينشِئ التابع <code>alert.set()‎</code> كلما أسندنا قيمة إلى <code>‎$alert</code>.
</p>

<p>
	النتيجة النهائية لذلك هي أنه يمكنك الوصول إلى المخازن العامة بالسهولة نفسها لاستخدام المتغيرات المحلية التفاعلية، ويُعَدّ ذلك مثالًا ممتازًا لكيفية وضع إطار Svelte المصرِّف مسؤولًا عن بيئة عمل أفضل للمطورين، ليس فقط من خلال إنقاذنا من كتابة شيفرة برمجية مكررة، وإنما من خلال إنشاء شيفرة برمجية أقل عرضةً للأخطاء أيضًا.
</p>

<h2>
	الكتابة في المخزن
</h2>

<p>
	الكتابة في المخزن هي مجرد مسألة استيراد هذا المخزن وتنفيذ <code>‎$store = 'new value'‎</code>، لذا لنستخدِم ذلك في المكوِّن <code>Todos</code>.
</p>

<p>
	أولًا، أضِف تعليمة الاستيراد التالية بعد تعليمات الاستيراد الأخرى الموجودة مسبقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_39" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../stores.js'</span></pre>

<p>
	عدّل الدالة <code>addTodo()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_41" style=""><span class="kwd">function</span><span class="pln"> addTodo</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[...</span><span class="pln">todos</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> newTodoId</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}]</span><span class="pln">
  $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Todo</span><span class="pln"> </span><span class="str">'${name}'</span><span class="pln"> has been added</span><span class="pun">`</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عدّل الدالة <code>removeTodo()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_43" style=""><span class="kwd">function</span><span class="pln"> removeTodo</span><span class="pun">(</span><span class="pln">todo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 todos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  todosStatus</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">()</span><span class="pln">             </span><span class="com">// انقل التركيز إلى عنوان الحالة</span><span class="pln">
  $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Todo</span><span class="pln"> </span><span class="str">'${todo.name}'</span><span class="pln"> has been deleted</span><span class="pun">`</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عدّل الدالة <code>updateTodo()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_45" style=""><span class="kwd">function</span><span class="pln"> updateTodo</span><span class="pun">(</span><span class="pln">todo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 </span><span class="kwd">const</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">findIndex</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">todos</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">name </span><span class="pun">!==</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">            $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">todo </span><span class="str">'${todos[i].name}'</span><span class="pln"> has been renamed to </span><span class="str">'${todo.name}'</span><span class="pun">`</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">todos</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">completed </span><span class="pun">!==</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">)</span><span class="pln">  $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">todo </span><span class="str">'${todos[i].name}'</span><span class="pln"> marked as $</span><span class="pun">{</span><span class="pln">todo</span><span class="pun">.</span><span class="pln">completed </span><span class="pun">?</span><span class="pln"> </span><span class="str">'completed'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'active'</span><span class="pun">}`</span><span class="pln">
  todos</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">todos</span><span class="pun">[</span><span class="pln">i</span><span class="pun">],</span><span class="pln"> </span><span class="pun">...</span><span class="pln">todo </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أضِف الكتلة التفاعلية التالية بعد الكتلة التي تبدأ بالتعليمة <code>let filter = 'all'‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_47" style=""><span class="pln">$</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="str">'all'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    $alert </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Browsing all to-dos'</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="str">'active'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    $alert </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Browsing active to-dos'</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="str">'completed'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    $alert </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Browsing completed to-dos'</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أخيرًا، عدّل الكتلتين <code>const checkAllTodos</code> و <code>const removeCompletedTodos</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_49" style=""><span class="kwd">const</span><span class="pln"> checkAllTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">completed</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">({...</span><span class="pln">t</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">}))</span><span class="pln">
  $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">completed </span><span class="pun">?</span><span class="pln"> </span><span class="str">'Checked'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'Unchecked'</span><span class="pun">}</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">todos</span><span class="pun">.</span><span class="pln">length</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">-</span><span class="pln">dos</span><span class="pun">`</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> removeCompletedTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  $alert </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Removed</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">).</span><span class="pln">length</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">-</span><span class="pln">dos</span><span class="pun">`</span><span class="pln">
  todos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لذلك استوردنا المخزن وحدّثناه في كل حدث، مما يتسبب في ظهور تنبيه جديد في كل مرة، وألقِ نظرةً على تطبيقك مرةً أخرى، وحاول إضافة أو حذف أو تحديث بعض المهام.
</p>

<p>
	سيشغّل إطار عمل Svelte التابع <code>alert.set()‎</code> كلما نفّذنا <code>‎$alert = ...‎</code>، إذ سيُرسَل إشعار إلى المكوِّن <code>Alert</code> -مثل أيّ مشترك آخر في مخزن التنبيهات <code>alert</code>- عندما يتلقى المخزن قيمةً جديدةً، وسيُحدَّث توصيفه بفضل خاصية التفاعل إطار عمل Svelte، كما يمكننا تطبيق الشيء نفسه ضمن أيّ مكوِّن أو ملف <code>‎.js</code>.
</p>

<p>
	<strong>ملاحظة</strong>: لا يمكنك استخدام الصيغة <code>‎$store</code> خارج مكونات Svelte لأن مصرِّف Svelte لن يستطيع الوصول إلى أيّ شيء خارج مكونات Svelte، لذا يجب عليك الاعتماد على التابعَين <code>store.subscribe()‎</code> و <code>store.set()‎</code>.
</p>

<h2>
	تحسين المكون Alert
</h2>

<p>
	يُعَدّ اضطرارك للنقر على التنبيه للتخلص منه أمرًا مزعجًا بعض الشيء، لذا يُفضَّل أن يختفي الإشعار بعد بضع ثوان، إذ سنحدد خاصيةً مقدَّرةً بالميلي ثانية للانتظار قبل مسح الإشعار، وسنحدّد مهلةً لإزالة التنبيه، كما سنهتم بمسح المهلة عند إلغاء تثبيت المكوِّن <code>Alert</code> لمنع تسرّب الذاكرة.
</p>

<p>
	أولًا، عدّل القسم <code>&lt;script&gt;</code> الخاص بالمكوِّن <code>Alert.svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_985_53" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> onDestroy </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte'</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../stores.js'</span><span class="pln">

  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> ms </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3000</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> visible
  </span><span class="kwd">let</span><span class="pln"> timeout

  </span><span class="kwd">const</span><span class="pln"> onMessageChange </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">message</span><span class="pun">,</span><span class="pln"> ms</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    clearTimeout</span><span class="pun">(</span><span class="pln">timeout</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">message</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">               </span><span class="com">// إخفاء التنبيه إذا كانت الرسالة فارغة</span><span class="pln">
      visible </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      visible </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">                                              </span><span class="com">// إظهار التنبيه</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ms </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> timeout </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> visible </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln"> ms</span><span class="pun">)</span><span class="pln"> </span><span class="com">// ‫وإخفائه بعد ms ميلي ثانية</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  $</span><span class="pun">:</span><span class="pln"> onMessageChange</span><span class="pun">(</span><span class="pln">$alert</span><span class="pun">,</span><span class="pln"> ms</span><span class="pun">)</span><span class="pln">      </span><span class="com">// شغّل الدالة‫ onMessageChange كلما تغير مخزن alert أو خاصيات ms</span><span class="pln">

  onDestroy</span><span class="pun">(()=&gt;</span><span class="pln"> clearTimeout</span><span class="pun">(</span><span class="pln">timeout</span><span class="pun">))</span><span class="pln">           </span><span class="com">// تأكد من تنظيف المهلة الزمنية</span><span class="pln">

</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	وعدّل قسم شيفرة HTML الخاصة بالمكوِّن <code>Alert.svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_985_55" style=""><span class="pln">{#if visible}
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> visible = false}&gt;
  </span><span class="tag">&lt;svg</span><span class="pln"> </span><span class="atn">xmlns</span><span class="pun">=</span><span class="atv">"http://www.w3.org/2000/svg"</span><span class="pln"> </span><span class="atn">viewBox</span><span class="pun">=</span><span class="atv">"0 0 20 20"</span><span class="tag">&gt;&lt;path</span><span class="pln"> </span><span class="atn">d</span><span class="pun">=</span><span class="atv">"M12.432 0c1.34 0 2.01.912 2.01 1.957 0 1.305-1.164 2.512-2.679 2.512-1.269 0-2.009-.75-1.974-1.99C9.789 1.436 10.67 0 12.432 0zM8.309 20c-1.058 0-1.833-.652-1.093-3.524l1.214-5.092c.211-.814.246-1.141 0-1.141-.317 0-1.689.562-2.502 1.117l-.528-.88c2.572-2.186 5.531-3.467 6.801-3.467 1.057 0 1.233 1.273.705 3.23l-1.391 5.352c-.246.945-.141 1.271.106 1.271.317 0 1.357-.392 2.379-1.207l.6.814C12.098 19.02 9.365 20 8.309 20z"</span><span class="tag">/&gt;&lt;/svg&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">{ $alert }</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
{/if}</span></pre>

<p>
	ننشئ هنا أولًا الخاصية <code>ms</code> بقيمة افتراضية 3000 (ميلي ثانية)، ثم ننشئ الدالة <code>onMessageChange()‎</code> التي ستهتم بالتحكم في ما إذا كان التنبيه مرئيًا أم لا، إذ نطلب من إطار عمل Svelte تشغيل هذه الدالة باستخدام <code>‎$: onMessageChange($alert, ms)‎</code> عند تغيير المخزن <code>‎$alert</code> أو الخاصية <code>ms</code>.
</p>

<p>
	كما سننظّف أيّ مهلة زمنية مُعلَّقة عندما يتغير المخزن <code>‎$alert</code>، فإذا كان المخزن <code>‎$alert</code> فارغًا، فسنضبط الخاصية <code>visible</code> على القيمة <code>false</code> وسيُزال التنبيه <code>Alert</code> من نموذج DOM؛ أما إذا لم يكن فارغًا، فسنضبط الخاصية <code>visible</code> على القيمة <code>true</code> وسنستخدِم الدالة <code>setTimeout()‎</code> لمسح التنبيه بعد مدة مقدارها <code>ms</code> ميلي ثانية.
</p>

<p>
	أخيرًا، نتأكد من استدعاء الدالة <code>clearTimeout()‎</code> باستخدام دالة دورة الحياة <code>onDestroy()‎</code>، كما أضفنا رمز SVG أعلى قسم التنبيه ليبدو أجمل.
</p>

<p>
	جرب التطبيق مرةً أخرى لترى كافة التغييرات.
</p>

<h2>
	جعل المكون Alert قابلا للوصول إليه
</h2>

<p>
	يعمل المكوِّن <code>Alert</code> بصورة جيدة، ولكنه ليس مناسبًا جدًا للتقنيات المساعدة، إذ تكمن المشكلة في العناصر التي تُضاف وتُزال من الصفحة ديناميكيًا، فيمكن ألّا تكون هذه العناصر واضحة جدًا لمستخدِمي التقنيات المساعدة مثل قارئات الشاشة، بالرغم من كونها واضحة من الناحية المرئية للمستخدِمين الذين يمكنهم رؤية الصفحة، كما يمكننا الاستفادة من <a href="https://academy.hsoub.com/programming/html/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D9%85%D9%88%D8%A7%D8%B5%D9%81%D8%A7%D8%AA-aria-%D8%A5%D8%B9%D8%B7%D8%A7%D8%A1-%D8%B9%D9%86%D8%A7%D8%B5%D8%B1-html-%D8%AF%D9%84%D8%A7%D9%84%D8%A7%D8%AA-%D8%AE%D8%A7%D8%B5%D8%A9-%D9%84%D8%AA%D8%B3%D9%87%D9%8A%D9%84-%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-r1327/" rel="">خاصيات مناطق ARIA الحية</a> التي توفر طريقةً لعرض تغييرات المحتوى الديناميكي برمجيًا لمعالجة هذه المواقف، بحيث يمكن أن تصل إليها التقنيات المساعِدة وتعلن عنها.
</p>

<p>
	يمكننا التصريح عن منطقة تحتوي على محتوى ديناميكي ويُعلَن عنها من خلال التقنيات المساعدة باستخدام السمة <code>aria-live</code> متبوعة بالإعداد المؤدّب Politeness الذي يُستخدَم لضبط الأولوية التي يجب أن تتعامل بها قارئات الشاشة مع تحديثات تلك المناطق، وتكون الإعدادات المُحتمَلة إما <code>off</code> أو <code>polite</code> أو <code>assertive</code>، كما لديك أيضًا العديد من قيم السمة <code>role</code> المتخصصة والمحدَّدة مسبقًا التي يمكن استخدامها مثل <code>log</code> و <code>status</code> و <code>alert</code>.
</p>

<p>
	ستؤدي إضافة السمة <code>role="alert"‎</code> إلى <a href="https://wiki.hsoub.com/HTML/div" rel="external">الحاوية &lt;div&gt;</a> في حالتنا إلى تنفيذ ما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_985_58" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">role</span><span class="pun">=</span><span class="atv">"alert"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> visible = false}&gt;</span></pre>

<p>
	يُعَدّ اختبار تطبيقاتك باستخدام قارئات الشاشة فكرةً جيدةً لاكتشاف مشاكل الشمولية وسهولة الوصول وللتعود على كيفية استخدام الأشخاص ذوي المشاكل البصرية للويب، كما لديك العديد من الخيارات مثل استخدام قارئ الشاشة <a href="https://www.nvaccess.org/" rel="external nofollow">NVDA</a> لنظام التشغيل ويندوز و<a href="https://support.google.com/chromebook/answer/7031755" rel="external nofollow">ChromeVox</a> للمتصفح كروم، و<a href="https://wiki.gnome.org/Projects/Orca" rel="external nofollow">Orca</a> على <a href="https://academy.hsoub.com/devops/linux/%D9%85%D8%A7-%D9%87%D9%88-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%8A%D9%86%D9%83%D8%B3%D8%9F-r451/" rel="">نظام لينكس</a>، و<a href="https://www.apple.com/accessibility/osx/voiceover/" rel="external nofollow">VoiceOver</a> لنظام التشغيل Mac OS X وiOS من بين خيارات أخرى.
</p>

<h2>
	استخدام مخزن لحفظ المهام
</h2>

<p>
	يتيح تطبيقنا الصغير إدارة مهامنا بسهولة تامة، ولكنه عديم الفائدة إذا حصلنا دائمًا على قائمة مهام ثابتة hardcoded نفسها عند إعادة تحميلها، لذا يجب معرفة كيفية استمرار مهامنا لجعلها مفيدة.
</p>

<p>
	يجب أولًا إيجاد طريقة ما لكي يعيد المكوِّن <code>Todos</code> المهام المُحدَّثة إلى المكوِّن الأب، إذ يمكننا إصدار حدث محدَّث مع قائمة المهام، ولكن يُعَدّ ربط المتغير <code>todos</code> أسهل، لذا لنفتح الملف <code>App.svelte</code> ونجرب ذلك.
</p>

<p>
	أضف أولًا السطر التالي بعد مصفوفة <code>todos</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_61" style=""><span class="pln">$</span><span class="pun">:</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'todos'</span><span class="pun">,</span><span class="pln"> todos</span><span class="pun">)</span></pre>

<p>
	عدّل بعد ذلك استدعاء المكون <code>Todos</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_985_63" style=""><span class="tag">&lt;Todos</span><span class="pln"> </span><span class="atn">bind:todos</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	<strong>ملاحظة</strong>: <code>&lt;Todos bind:todos /‎&gt;</code> هو مجرد اختصار للتعليمة <code>&lt;Todos bind:todos={todos} /‎&gt;</code>.
</p>

<p>
	ارجع إلى تطبيقك وحاول إضافة بعض المهام، ثم انتقل إلى طرفية الويب الخاصة بأدوات المطور، حيث ستلاحظ أنّ كل تعديل نجريه على مهامنا ينعكس على المصفوفة <code>todos</code> المُعرَّفة في الملف <code>App.svelte</code> بفضل الموجّه <code>bind</code>.
</p>

<p>
	يجب الآن إيجاد طريقة لحفظ هذه المهام، إذ يمكننا تطبيق شيفرة برمجية في المكوِّن <code>App.svelte</code> لقراءة مهامنا وحفظها في تخزين الويب أو خدمة الويب، لكن يمكن أن يكون من الأفضل أن نطور مخزنًا عامًا يسمح بحفظ محتواه، إذ يمكن استخدامه مثل أيّ مخزن آخر تمامًا وتجريد آلية استمرار، كما يمكننا إنشاء مخزن يزامن محتواه مع تخزين الويب، ثم تطوير مخزن آخر لاحقًا يتزامن مع خدمة الويب، وسيكون التبديل بينهما أمرًا بسيطًا ولن نضطر إلى تعديل المكوِّن <code>App.svelte</code> على الإطلاق.
</p>

<h3>
	حفظ المهام
</h3>

<p>
	لنبدأ باستخدام مخزن عادي قابل للكتابة لحفظ مهامنا.
</p>

<p>
	افتح الملف <code>stores.js</code> وأضِف المخزن التالي بعد المخزن الموجود مسبقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_65" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> todos </span><span class="pun">=</span><span class="pln"> writable</span><span class="pun">([])</span></pre>

<p>
	يجب الآن استيراد المخزن واستخدامه في الملف <code>Alert.svelte</code>، وتذكّر أنه يجب استخدام صيغة المخزن <code>‎$todos</code> التفاعلية للوصول إلى المهام الآن، لذا عدّل الملف<code> Alert.svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_67" style=""><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Todos</span><span class="pln"> from </span><span class="str">"./components/Todos.svelte"</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Alert</span><span class="pln"> from </span><span class="str">"./components/Alert.svelte"</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> todos </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"./stores.js"</span><span class="pun">;</span><span class="pln">

  $todos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Create a Svelte starter app"</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Create your first component"</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Complete the rest of the tutorial"</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">];</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="typ">Alert</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="typ">Todos</span><span class="pln"> bind</span><span class="pun">:</span><span class="pln">todos</span><span class="pun">={</span><span class="pln">$todos</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span></pre>

<p>
	جرب تطبيقك الآن، إذ يجب أن يعمل كل شيء بصورة جيدة، وسنرى بعد ذلك كيفية تعريف مخازننا المُخصَّصة.
</p>

<h3>
	كيفية إنشاء مخزن
</h3>

<p>
	يمكنك إنشاء مخازنك الخاصة دون الاعتماد على الوحدة <code>svelte/store</code> من خلال تنفيذ مخزن تعمل ميزاته على النحو التالي:
</p>

<ol>
	<li>
		يجب أن يحتوي المخزن على التابع <code>subscribe()‎</code> الذي يجب أن يقبل دالة اشتراك بوصفها وسيطًا له، ويجب استدعاء جميع دوال الاشتراك النشطة في المخزن عندما تتغير قيمة المخزن.
	</li>
	<li>
		يجب أن تعيد الدالةُ <code>subscribe()‎</code> الدالةَ <code>unsubscribe()‎</code> التي يجب أن توقف الاشتراك عند استدعائها.
	</li>
	<li>
		يمكن أن يحتوي المخزن اختياريًا على التابع <code>set()‎</code> الذي يجب أن يقبل قيمة المخزن الجديدة على أساس وسيط له، والذي يستدعي بطريقة متزامنة جميع دوال الاشتراك النشطة في المخزن، كما يُطلَق على المخزن الذي يحتوي على التابع <code>set()‎</code> اسم مخزن قابل للكتابة.
	</li>
</ol>

<p>
	أولًا، أضِف تعليمات <code>console.log()‎</code> التالية إلى المكوِّن <code>App.svelte</code> لرؤية مخزن <code>todos</code> ومحتواه أثناء العمل، لذا أضِف الأسطر التالية بعد المصفوفة <code>todos</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_69" style=""><span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'todos store - todos:'</span><span class="pun">,</span><span class="pln"> todos</span><span class="pun">)</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'todos store content - $todos:'</span><span class="pun">,</span><span class="pln"> $todos</span><span class="pun">)</span></pre>

<p>
	سترى شيئًا يشبه ما يلي في طرفية الويب عند تشغيل التطبيق:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="116346" href="https://academy.hsoub.com/uploads/monthly_2023_01/02-svelte-store-in-action.png.9bf4da6efe4d58b278befaab3ed1b0a7.png" rel=""><img alt="طرفية الويب عند تشغيل التطبيق" class="ipsImage ipsImage_thumbnailed" data-fileid="116346" data-ratio="24.49" data-unique="9kywlco4m" style="width: 780px; height: 191px;" width="700" src="https://academy.hsoub.com/uploads/monthly_2023_01/02-svelte-store-in-action.png.9bf4da6efe4d58b278befaab3ed1b0a7.png"> </a>
</p>

<p>
	يُعَدّ مخزننا مجرد كائن يحتوي على التوابع <code>subscribe()‎</code> و <code>set()‎</code> و <code>update()‎</code>، وتُعَدّ <code>‎$todos</code> مصفوفة المهام.
</p>

<p>
	إليك مخزن أساسي مُطبَّق من الصفر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_73" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> writable </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">initial_value </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> value </span><span class="pun">=</span><span class="pln"> initial_value         </span><span class="com">// محتوى المخزن</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> subs </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">                     </span><span class="com">// معالجات المشتركين</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> subscribe </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">handler</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    subs </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[...</span><span class="pln">subs</span><span class="pun">,</span><span class="pln"> handler</span><span class="pun">]</span><span class="pln">                                 </span><span class="com">// أضِف معالجًا إلى مصفوفة المشتركين</span><span class="pln">
    handler</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln">                                            </span><span class="com">// استدعِ المعالج باستخدام القيمة الحالية</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> subs </span><span class="pun">=</span><span class="pln"> subs</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">sub </span><span class="pun">=&gt;</span><span class="pln"> sub </span><span class="pun">!==</span><span class="pln"> handler</span><span class="pun">)</span><span class="pln">   </span><span class="com">// إعادة دالة إلغاء الاشتراك</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">new_value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value </span><span class="pun">===</span><span class="pln"> new_value</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pln">         </span><span class="com">// إذا كانت القيمة نفسها، فاخرج</span><span class="pln">
    value </span><span class="pun">=</span><span class="pln"> new_value                       </span><span class="com">// حدّث القيمة</span><span class="pln">
    subs</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">sub </span><span class="pun">=&gt;</span><span class="pln"> sub</span><span class="pun">(</span><span class="pln">value</span><span class="pun">))</span><span class="pln">         </span><span class="com">// حدّث المشتركين</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> update </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">update_fn</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">(</span><span class="pln">update_fn</span><span class="pun">(</span><span class="pln">value</span><span class="pun">))</span><span class="pln">   </span><span class="com">// حدّث الدالة</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> subscribe</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">,</span><span class="pln"> update </span><span class="pun">}</span><span class="pln">       </span><span class="com">// عَقد المخزن</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نصرّح في الشيفرة السابقة عن <code>subs</code> والتي هي مصفوفة من المشتركين، كما نضيف في التابع <code>subscribe()‎</code> المعالج إلى المصفوفة <code>subs</code> ونعيد دالةً ستزيل المعالج من المصفوفة عند تنفيذها، كما نحدّث قيمة المخزن ونستدعي كل معالج عند استدعاء التابع <code>set()‎</code> من خلال تمرير القيمة الجديدة بوصفها معاملًا.
</p>

<p>
	لا نطبّق المخازن عادةً من الصفر، وإنما يمكنك استخدام المخزن القابل للكتابة لإنشاء متاجر مخصَّصة باستخدام شيفرة برمجية محدَّدة النطاق، وسننشئ في المثال التالي مخزنًا لعدّاد يسمح بإضافة واحد إلى العدّاد أو إعادة ضبط قيمته فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_75" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> writable </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte/store'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> myStore</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> subscribe</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">,</span><span class="pln"> update </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> writable</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    subscribe</span><span class="pun">,</span><span class="pln">
    addOne</span><span class="pun">:</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> update</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">),</span><span class="pln">
    reset</span><span class="pun">:</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا أصبح تطبيق قائمة المهام معقدًا للغاية، فيمكننا السماح لمخزن المهام بمعالجة كل تعديل للحالة، إذ يمكننا نقل جميع التوابع التي تعدل مصفوفة <code>todos</code> مثل التابعَين <code>addTodo()‎</code> و <code>removeTodo()‎</code> وغير ذلك من المكوِّن <code>Todo</code> إلى المخزن، فإذا كان لديك مكان مركزي لتطبيق جميع تعديلات الحالة، فيمكن للمكونات استدعاء هذه التوابع فقط لتعديل حالة التطبيق وعرض المعلومات التي يسمح المخزن بالوصول إليها بصورة تفاعلية، إذ يسهّل وجود مكان فريد لمعالجة تعديلات الحالة التفكيرَ بشأن مشكلات تدفق الحالة وتحديدها.
</p>

<p>
	لن يجبرك إطار عمل Svelte على تنظيم إدارة حالتك بطريقة معينة، وإنما يوفِّر الأدوات لاختيار كيفية معالجتها.
</p>

<h3>
	تنفيذ مخزننا المخصص للمهام
</h3>

<p>
	لا يُعَدّ تطبيق قائمة المهام معقدًا، لذلك لن ننقل جميع توابع التعديل إلى مكان مركزي، وإنما سنتركها كما هي، وسنركز على استمرار مهامنا بدلًا من ذلك.
</p>

<p>
	<strong>ملاحظة</strong>: إذا أردت تتبّع هذا المقال باستخدام الأداة Svelte REPL، فلن تتمكن من إكمال هذه الخطوة، إذ تعمل Svelte REPL في بيئة وضع الحماية التي لن تسمح لك بالوصول إلى تخزين الويب، وستحصل على خطأ "العملية غير آمنة The operation is insecure"، وعلى هذا الأساس لا بد من استنساخ المستودع والانتقال إلى المجلد الآتي: mdn-svelte-tutorial/06-stores أو يمكنك تنزيل محتوى المجلد مباشرةً باستخدام الأمر الآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1618_6" style=""><span class="pln"> npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">06</span><span class="pun">-</span><span class="pln">stores</span></pre>

<p>
	يمكنك تطبيق مخزن مخصص يحفظ محتواه في تخزين الويب من خلال استخدام مخزن قابل للكتابة يطبّق ما يلي:
</p>

<ul>
	<li>
		يقرأ القيمة من تخزين الويب في البداية ويهيئها بقيمة افتراضية إذا لم تكن موجودةً.
	</li>
	<li>
		يحدّث المخزن نفسه والبيانات الموجودة في التخزين المحلي عند تعديل القيمة.
	</li>
</ul>

<p>
	يدعم تخزين الويب حفظ قيم <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D8%A7%D9%84%D9%86%D8%B5%D9%8A%D8%A9-strings-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r817/" rel="">السلاسل النصية</a> فقط، لذا يجب تحويلها من كائن إلى سلسلة نصية عند الحفظ، والعكس صحيح عند تحميل القيمة من التخزين المحلي.
</p>

<p>
	أولًا، أنشئ ملفًا جديدًا بالاسم <code>localStore.js</code> في المجلد <code>src</code>.
</p>

<p>
	ثانيًا، ضع فيه المحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_78" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> writable </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte/store'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> localStore </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> initial</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                 </span><span class="com">// يتلقى مفتاح التخزين المحلي وقيمة أولية</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> toString </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">  </span><span class="com">// دالة مساعدة</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> toObj </span><span class="pun">=</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">parse                                    </span><span class="com">// دالة مساعدة</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">getItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">)</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                   </span><span class="com">// العنصر غير موجود في التخزين المحلي</span><span class="pln">
    localStorage</span><span class="pun">.</span><span class="pln">setItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> toString</span><span class="pun">(</span><span class="pln">initial</span><span class="pun">))</span><span class="pln">              </span><span class="com">// تهيئة التخزين المحلي بالقيمة الأولية</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> saved </span><span class="pun">=</span><span class="pln"> toObj</span><span class="pun">(</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">getItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">))</span><span class="pln">              </span><span class="com">// تحويل إلى كائن</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> subscribe</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">,</span><span class="pln"> update </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> writable</span><span class="pun">(</span><span class="pln">saved</span><span class="pun">)</span><span class="pln">          </span><span class="com">// إنشاء المتجر الأساسي القابل للكتابة</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    subscribe</span><span class="pun">,</span><span class="pln">
    </span><span class="kwd">set</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      localStorage</span><span class="pun">.</span><span class="pln">setItem</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> toString</span><span class="pun">(</span><span class="pln">value</span><span class="pun">))</span><span class="pln">              </span><span class="com">// حفظ القيمة في التخزين المحلي كسلسلة نصية</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    update
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنشرح الشيفرة البرمجية السابقة:
</p>

<ul>
	<li>
		ستكون<code>localStore</code> دالةً تقرأ محتواها من تخزين الويب أولًا وتعيد كائنًا مع ثلاث توابع هي <code>subscribe()‎</code> و <code>set()‎</code> و <code>update()‎</code> عند تنفيذها.
	</li>
	<li>
		يجب تحديد مفتاح تخزين الويب وقيمة أولية عند إنشاء دالة <code>localStore</code> جديدة، ثم نتحقق مما إذا كانت القيمة موجودة في تخزين الويب، وننشئها إذا لم يكن الأمر كذلك.
	</li>
	<li>
		نستخدِم التابعَين <code>localStorage.getItem(key)‎</code> و <code>localStorage.setItem(key, value)‎</code> لقراءة المعلومات وكتابتها في تخزين الويب، كما نستخدِم الدالتين المساعدتين <code>toString()‎</code> و <code>toObj()‎</code> (التي تستخدم التابع <code>JSON.parse()‎</code>) لتحويل القيم.
	</li>
	<li>
		نحوّل بعد ذلك المحتوى المُستلمَ من تخزين الويب من سلسلة نصية إلى كائن، ونحفظ هذا الكائن في مخزننا.
	</li>
	<li>
		أخيرًا، نحدّث تخزين الويب مع تحويل القيمة إلى سلسلة نصية في كل مرة نحدّث فيها محتويات المخزن.
	</li>
</ul>

<p>
	لاحظ أنه كان علينا فقط إعادة تعريف التابع <code>set()‎</code> من خلال إضافة العملية لحفظ القيمة في تخزين الويب، وما تبقى من الشيفرة البرمجية في أغلبه هو عبارة عن تهيئة وتحويل.
</p>

<p>
	سنستخدِم الآن المخزن المحلي في<code> stores.js</code> لإنشاء مخزن المهام المستمر محليًا، لذا عدّل الملف<code> stores.js</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_80" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> writable </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte/store'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> localStore </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./localStore.js'</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> alert </span><span class="pun">=</span><span class="pln"> writable</span><span class="pun">(</span><span class="str">'Welcome to the to-do list app!'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> initialTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Visit MDN web docs'</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Complete the Svelte Tutorial'</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
</span><span class="pun">]</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> todos </span><span class="pun">=</span><span class="pln"> localStore</span><span class="pun">(</span><span class="str">'mdn-svelte-todo'</span><span class="pun">,</span><span class="pln"> initialTodos</span><span class="pun">)</span></pre>

<p>
	هيّأنا المخزن لحفظ البيانات في تخزين الويب ليكون تابعًا للمفتاح <code>mdn-svelte-todo</code> باستخدام الدالة الآتية:
</p>

<pre class="ipsCode" id="ips_uid_6793_7"> localStore('mdn-svelte-todo', initialTodos)‎</pre>

<p>
	كما ضبطنا بعض المهام لتكون قيمًا أوليةً.
</p>

<p>
	لنتخلص الآن من المهام الثابتة في المكوِّن <code>App.svelte</code>، لذا حدّث محتوياته كما يلي، حيث سنحذف فقط المصفوفة <code>‎$todos</code> وتعليمات <code>console.log()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_985_84" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Todos</span><span class="pln"> from </span><span class="str">'./components/Todos.svelte'</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Alert</span><span class="pln"> from </span><span class="str">'./components/Alert.svelte'</span><span class="pln">

  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> todos </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./stores.js'</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;Alert</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
</span><span class="tag">&lt;Todos</span><span class="pln"> </span><span class="atn">bind:todos</span><span class="pun">=</span><span class="atv">{$todos}</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	<strong>ملاحظة</strong>: يُعَدّ ذلك التغيير الوحيد الذي يجب إجراؤه لاستخدام مخزننا المُخصَّص، فالمكون <code>App.svelte</code> واضح تمامًا من حيث نوع المخزن الذي نستخدِمه.
</p>

<p>
	جرّب تطبيقك مرةً أخرى، وأنشئ بعض المهام ثم أغلق المتصفح، كما يمكنك إيقاف خادم Svelte وإعادة تشغيله، حيث ستظل مهامك موجودة عند إعادة زيارة عنوان URL.
</p>

<p>
	كما يمكنك فحص تطبيقك في طرفية أدوات التطوير DevTools من خلال إدخال الأمر <code>localStorage.getItem('mdn-svelte-todo')‎</code>، لذا طبّق بعض التغييرات على تطبيقك مثل الضغط على زر "إلغاء تحديد الكل Uncheck All" وتحقق من محتوى تخزين الويب مرةً أخرى، وستحصل على شيء يشبه ما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="116347" href="https://academy.hsoub.com/uploads/monthly_2023_01/03-persisting-todos-to-local-storage.png.d2328f5cc44e2c34d337fc88f5c4e224.png" rel=""><img alt="التحقق من محتوى تخزين الويب " class="ipsImage ipsImage_thumbnailed" data-fileid="116347" data-ratio="71.51" data-unique="njyxflk3t" style="width: 730px; height: auto;" width="700" src="https://academy.hsoub.com/uploads/monthly_2023_01/03-persisting-todos-to-local-storage.thumb.png.7e25fcae6c886b27174bb1287f59388f.png"> </a>
</p>

<p>
	توفِّر مخازن Svelte طريقةً بسيطةً جدًا وخفيفة الوزن ولكنها قوية للغاية للتعامل مع حالة التطبيق المعقدة من مخزن بيانات عام بطريقة تفاعلية، ويمكن أن يوفِّر إطار عمل Svelte صيغة الاشتراك التلقائي <code>‎$store</code> التي تسمح لنا بالعمل مع المخازن باستخدام الطريقة نفسها للتعامل مع المتغيرات المحلية لأن إطار عمل Svelte يصرِّف الشيفرة، كما تمتلك المخازن الحد الأدنى من <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api%D8%9F-r1512/" rel="">واجهة برمجة التطبيقات</a>، مما يؤدي إلى سهولة إنشاء مخازننا المُخصَّصة لتجريد عمل المخزن الداخلي.
</p>

<h2>
	الانتقالات
</h2>

<p>
	لنضِف الآن حركةً إلى التنبيهات، إذ يوفر إطار عمل Svelte وحدةً كاملةً لتعريف الانتقالات transitions والحركات animations لنتمكن من جعل واجهات المستخدِم أكثر جاذبيةً.
</p>

<p>
	يمكن تطبيق الانتقالات باستخدام الموجّه <code>transition:fn</code> الذي يعمل عند دخول عنصر إلى نموذج DOM أو مغادرته بوصفه نتيجةً لتغيير الحالة، إذ تصدّر الوحدة <code>svelte/transition</code> سبع دوال هي <code>fade</code> و <code>blur</code> و <code>fly</code> و <code>slide</code> و <code>scale</code> و <code>draw</code> و <code>crossfade</code>.
</p>

<p>
	لنعطِ المكوِّن <code>Alert</code> انتقالًا <code>transition</code> من النوع <code>fly</code>، لذا افتح الملف <code>Alert.svelte </code>واستورد الدالة <code>fly</code> من الوحدة <code>svelte/transition</code>.
</p>

<p>
	أولًا، ضع تعليمة الاستيراد التالية بعد تعليمات الاستيراد الموجودة مسبقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_89" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> fly </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte/transition'</span></pre>

<p>
	ثانيًا، عدّل <a href="https://wiki.hsoub.com/HTML/div" rel="external">وسم الفتح &lt;div&gt;</a> كما يلي لاستخدام هذا الانتقال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_985_95" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">role</span><span class="pun">=</span><span class="atv">"alert"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> visible = false}
  transition:fly
&gt;</span></pre>

<p>
	يمكن أن تأخذ الانتقالات معامِلات كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_985_93" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">role</span><span class="pun">=</span><span class="atv">"alert"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> visible = false}
  transition:fly="{{delay: 250, duration: 300, x: 0, y: -100, opacity: 0.5}}"
&gt;</span></pre>

<p>
	<strong>ملاحظة</strong>: لا تُعَدّ الأقواس المزدوجة المعقوصة صيغةً خاصةً بإطار عمل Svelte، وإنما هي مجرد كائن جافاسكربت حرفي يُمرَّر بوصفه معامِلًا للانتقال <code>fly</code>.
</p>

<p>
	جرب تطبيقك مرةً أخرى، وسترى أنّ الإشعارات الآن أكثر جاذبيةً.
</p>

<p>
	<strong>ملاحظة</strong>: يسمح إطار عمل Svelte بتحسين حجم الحزمة من خلال استبعاد الميزات غير المستخدَمة لكونه مصرِّفًا، فإذا صرّفنا تطبيقنا للإنتاج باستخدام الأمر <code>npm run build</code>، فسيكون وزن الملف <code>public/build/bundle.js</code> أقل بقليل من 22 كيلوبايت، وإذا أزلنا الموجِّه <code>transitions:fly</code>، فإنّ إطار عمل Svelte ذكي بما يكفي لإدراك عدم استخدام الدالة <code>fly</code>، وسينخفض حجم الملف bundle.js إلى 18 كيلوبايت فقط.
</p>

<p>
	ما هذا سوى غيض من فيض، إذ يمتلك إطار عمل Svelte الكثير من الخيارات للتعامل مع الحركات والانتقالات، كما يدعم تحديد انتقالات مختلفة لتطبيقها عند إضافة العنصر أو إزالته من نموذج DOM باستخدام الموجِّه <code>in:fn</code> أو <code>out:fn</code>، ويتيح تعريف انتقالات CSS وجافاسكربت المُخصَّصة، كما لديه العديد من دوال تحسين الحركة Easing لتحديد معدل التغيير بمرور الوقت، ويمكنك إلقاء نظرة على <a href="https://svelte.dev/examples/hello-world#easing" rel="external nofollow">أداة تحسين الحركة البصرية ease visualizer</a> لاستكشاف دوال تحسين الحركة المتاحة المختلفة.
</p>

<p>
	يمكنك الوصول إلى نسختك من مستودعنا على النحو التالي لمعرفة حالة الشيفرة كما يجب أن تكون في نهاية هذا المقال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_97" style=""><span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">07</span><span class="pun">-</span><span class="pln">next</span><span class="pun">-</span><span class="pln">steps</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_985_99" style=""><span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">07</span><span class="pun">-</span><span class="pln">next</span><span class="pun">-</span><span class="pln">steps</span></pre>

<p>
	تذكَّر تشغيل الأمر <code>npm install &amp;&amp; npm run dev</code> لبدء تشغيل تطبيقك في وضع التطوير، فإذا أردت متابعتنا، فابدأ بكتابة الشيفرة باستخدام الأداة REPL من <a href="https://svelte.dev/repl/378dd79e0dfe4486a8f10823f3813190?version=3.23.2" rel="external nofollow">هنا</a>.
</p>

<h2>
	الخلاصة
</h2>

<p>
	أضفنا في هذا المقال ميزتين جديدتين هما المكوِّن <code>Alert</code> واستمرار المهام <code>todos</code> في تخزين الويب.
</p>

<ul>
	<li>
		سمح لنا ذلك بعرض بعض تقنيات إطار عمل Svelte المتقدمة، كما طوّرنا المكوِّن <code>Alert</code> لإظهار كيفية تطبيق إدارة الحالة عبر المكونات باستخدام المخازن Stores، ورأينا كيفية الاشتراك التلقائي في المخازن لدمجها بسلاسة مع نظام Svelte التفاعلي.
	</li>
	<li>
		رأينا بعد ذلك كيفية تطبيق مخزننا الخاص من الصفر وكيفية توسيع مخزن Svelte القابل للكتابة لاستمرار البيانات في تخزين الويب.
	</li>
	<li>
		ألقينا في النهاية نظرةً على استخدام الموجِّه <code>transition</code> في إطار عمل Svelte لتطبيق الحركات على عناصر DOM.
	</li>
</ul>

<p>
	سنتعرّف في مقال قادم على كيفية إضافة دعم <a href="https://academy.hsoub.com/programming/javascript/typescript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-typescript-r1214/" rel="">لغة TypeScript</a> إلى تطبيق Svelte، كما سننقل تطبيقنا بالكامل إلى TypeScript للاستفادة من جميع ميزاتها.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_stores" rel="external nofollow">Working with Svelte stores</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D9%81%D8%A7%D8%B9%D9%84%D9%8A%D8%A9-%D9%88%D8%AF%D9%88%D8%B1%D8%A9-%D8%A7%D9%84%D8%AD%D9%8A%D8%A7%D8%A9-%D9%88%D8%B3%D9%87%D9%88%D9%84%D8%A9-%D9%88%D8%B5%D9%88%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%8A%D9%86-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1863/" rel="">التفاعلية ودورة الحياة وسهولة وصول المستخدمين في إطار عمل Svelte</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">بدء استخدام إطار العمل Svelte لبناء تطبيقات ويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1811/" rel="">إنشاء تطبيق قائمة مهام باستعمال إطار عمل Svelte</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1822/" rel="">التعامل مع المتغيرات والخاصيات في إطار عمل Svelte</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%82%D8%B3%D9%8A%D9%85-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-svelte-%D8%A5%D9%84%D9%89-%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-r1823/" rel="">تقسيم تطبيق Svelte إلى مكونات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1864</guid><pubDate>Fri, 27 Jan 2023 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x641;&#x627;&#x639;&#x644;&#x64A;&#x629; &#x648;&#x62F;&#x648;&#x631;&#x629; &#x627;&#x644;&#x62D;&#x64A;&#x627;&#x629; &#x648;&#x633;&#x647;&#x648;&#x644;&#x629; &#x648;&#x635;&#x648;&#x644; &#x627;&#x644;&#x645;&#x633;&#x62A;&#x62E;&#x62F;&#x645;&#x64A;&#x646; &#x641;&#x64A; &#x625;&#x637;&#x627;&#x631; &#x639;&#x645;&#x644; Svelte</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D9%81%D8%A7%D8%B9%D9%84%D9%8A%D8%A9-%D9%88%D8%AF%D9%88%D8%B1%D8%A9-%D8%A7%D9%84%D8%AD%D9%8A%D8%A7%D8%A9-%D9%88%D8%B3%D9%87%D9%88%D9%84%D8%A9-%D9%88%D8%B5%D9%88%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%8A%D9%86-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1863/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/1408325360_---Svelte-_-----.png.4e6eec1187aa981523639045279de1bf.png" /></p>
<p>
	أضفنا في مقال تقسيم تطبيق Svelte إلى مكونات من هذه السلسلة مزيدًا من الميزات إلى قائمة المهام وبدأنا بتنظيم تطبيقنا ضمن مكونات، وسنضيف في هذا المقال الميزات النهائية لتطبيقنا مع استكمال تقسيمه إلى مكونات، وسنتعلم كيفية التعامل مع مشاكل التفاعل المتعلقة بتحديث الكائنات والمصفوفات، كما سنتعرّف على حل بعض مشاكل تركيز سهولة الوصول أو الشمولية أي سهولة وصول كل المستخدِمين خصوصًا من يملك بعض الإعاقات وغير ذلك.
</p>

<ul>
	<li>
		<strong>المتطلبات الأساسية</strong>: يوصَى على الأقل بأن تكون على دراية بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة باستخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471" rel="">سطر الأوامر أو الطرفية</a>، وستحتاج طرفية مثبَّت عليها node و npm لتصريف وبناء تطبيقك.
	</li>
	<li>
		<strong>الهدف</strong>: تعلّم بعض تقنيات Svelte المتقدمة التي تتضمن حل مشاكل التفاعل ومشاكل سهولة الوصول لمستخدِمي لوحة المفاتيح المتعلقة بدورة حياة المكونات وغير ذلك.
	</li>
</ul>

<p>
	سنركز على بعض مشاكل سهولة الوصول التي تتضمن إدارة التركيز، إذ سنستخدِم بعض التقنيات للوصول إلى عُقد <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">نموذج DOM</a> وتنفيذ توابع مثل التابعَين <code>focus()‎</code> و <code>select()‎</code>، كما سنرى كيفية التصريح عن تنظيف مستمعي الأحداث على عناصر DOM، كما سنتعلّم بعض الأمور عن دورة حياة المكونات لفهم متى تُثبَّت عُقد DOM ومتى تُفصَل من نموذج DOM وكيف يمكننا الوصول إليها، كما سنتعرف على الموجه <code>action</code> الذي سيسمح بتوسيع وظائف عناصر <a href="https://academy.hsoub.com/programming/html/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-html-r1687/" rel="">HTML</a> بطريقة قابلة لإعادة الاستخدام والتصريح.
</p>

<p>
	أخيرًا، سنتعلم المزيد عن المكونات، فقد رأينا سابقًا كيف يمكن للمكونات مشاركة البيانات باستخدام الخاصيات Props والتواصل مع المكونات الآباء باستخدام الأحداث وربط البيانات ثنائي الاتجاه، وسنرى الآن كيف يمكن للمكونات الوصول إلى التوابع والمتغيرات.
</p>

<p>
	سنطوّر المكونات الجديدة التالية خلال هذا المقال:
</p>

<ul>
	<li>
		<code>MoreActions</code>: يعرض الزرين "تحديد الكل Check All" و"حذف المهام المكتملة Remove Completed" ويصدر الأحداث المقابلة المطلوبة للتعامل مع وظائفهما.
	</li>
	<li>
		<code>NewTodo</code>: يعرض حقل الإدخال <code>&lt;input&gt;</code> وزر "الإضافة Add" لإضافة مهمة جديدة.
	</li>
	<li>
		<code>TodosStatus</code>: عرض عنوان الحالة "x out of y items completed" التي تمثِّل المهام المكتملة.
	</li>
</ul>

<p>
	يمكن متابعة كتابة شيفرتك معنا، لذلك انسخ أولًا مستودع github -إذا لم تفعل ذلك مسبقًا- باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_11" style=""><span class="pln">git clone https</span><span class="pun">:</span><span class="com">//github.com/opensas/mdn-svelte-tutorial.git</span></pre>

<p>
	ثم يمكنك الوصول إلى حالة التطبيق الحالية من خلال تشغيل الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_13" style=""><span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">05</span><span class="pun">-</span><span class="pln">advanced</span><span class="pun">-</span><span class="pln">concepts</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_16" style=""><span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">05</span><span class="pun">-</span><span class="pln">advanced</span><span class="pun">-</span><span class="pln">concepts</span></pre>

<p>
	تذكَّر تشغيل الأمر <code>npm install &amp;&amp; npm run dev</code> لبدء تشغيل تطبيقك في وضع التطوير، فإذا أردت متابعتنا، فابدأ بكتابة الشيفرة باستخدام الأداة REPL من <a href="https://svelte.dev/repl/76cc90c43a37452e8c7f70521f88b698?version=3.23.2" rel="external nofollow">svelte.dev</a>.
</p>

<h2>
	المكون MoreActions
</h2>

<p>
	سنعالج الآن الزرين "تحديد الكل Check All" و"حذف المهام المكتملة Remove Completed"، لذا لننشئ مكونًا يكون مسؤولًا عن عرض الأزرار وإصدار الأحداث المقابلة.
</p>

<p>
	أولًا، أنشئ ملفًا جديدًا بالاسم <code>components/MoreActions.svelte</code>.
</p>

<p>
	ثانيًا، سنرسل الحدث <code>checkAll</code> عند النقر على الزر الأول للإشارة إلى أنه يجب تحديد أو إلغاء تحديد جميع المهام، كما سنرسل الحدث <code>removeCompleted</code> عند النقر على الزر الثاني للإشارة إلى أنه يجب حذف جميع المهام المكتملة، لذا ضَع المحتوى التالي في الملف MoreActions.svelte:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_25" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createEventDispatcher </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte'</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> createEventDispatcher</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> completed </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> checkAll </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    dispatch</span><span class="pun">(</span><span class="str">'checkAll'</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">)</span><span class="pln">
    completed </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">completed
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> removeCompleted </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> dispatch</span><span class="pun">(</span><span class="str">'removeCompleted'</span><span class="pun">)</span><span class="pln">

</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{checkAll}</span><span class="tag">&gt;</span><span class="pln">{completed ? 'Check' : 'Uncheck'} all</span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{removeCompleted}</span><span class="tag">&gt;</span><span class="pln">Remove completed</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	ضمّنا المتغير <code>completed</code> للتبديل بين تحديد جميع المهام وإلغاء تحديدها.
</p>

<p>
	ثالثًا، سنستورد المكوِّن <code>MoreActions</code> مرةً أخرى في <code>Todos.svelte</code> وسننشئ دالتين للتعامل مع الأحداث الصادرة من المكوِّن <code>MoreActions</code>، لذا أضف تعليمة الاستيراد التالية بعد تعليمات الاستيراد الموجودة مسبقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_27" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">MoreActions</span><span class="pln"> from </span><span class="str">'./MoreActions.svelte'</span></pre>

<p>
	رابعًا، أضف بعد ذلك الدوال الموضَّحة في نهاية القسم <code>&lt;script&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_29" style=""><span class="kwd">const</span><span class="pln"> checkAllTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">completed</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed </span><span class="pun">=</span><span class="pln"> completed</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> removeCompletedTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> todos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">)</span></pre>

<p>
	خامسًا، انتقل الآن إلى الجزء السفلي من شيفرة HTML الخاصة بـ <code>Todos.svelte</code> واستبدل <a href="https://wiki.hsoub.com/HTML/div" rel="external">العنصر &lt;div&gt;</a> الذي له الصنف <code>btn-group</code> والذي نسخناه إلى MoreActions.svelte باستدعاء المكوِّن <code>MoreActions</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_38" style=""><span class="com">&lt;!-- MoreActions --&gt;</span><span class="pln">
</span><span class="tag">&lt;MoreActions</span><span class="pln">
  </span><span class="atn">on:checkAll</span><span class="pun">=</span><span class="atv">{e</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> checkAllTodos(e.detail)}
  on:removeCompleted={removeCompletedTodos}
/&gt;</span></pre>

<p>
	سادسًا، لنعد إلى التطبيق ونجربه، إذ ستجد أنّ زر "حذف المهام المكتملة Remove Completed" يعمل بصورة جيدة، ولكن يفشل الزر "تحديد الكل Check All" أو "إلغاء تحديد الكل Uncheck All".
</p>

<h2>
	اكتشاف التفاعل: تحديث الكائنات والمصفوفات
</h2>

<p>
	يمكننا تسجيل المصفوفة <code>todos</code> من الدالة <code>checkAllTodos()‎</code> إلى الطرفية لمعرفة ما يحدث.
</p>

<p>
	أولًا، عدّل الدالة <code>checkAllTodos()‎</code> إلى ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_41" style=""><span class="kwd">const</span><span class="pln"> checkAllTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">completed</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed </span><span class="pun">=</span><span class="pln"> completed</span><span class="pun">);</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'todos'</span><span class="pun">,</span><span class="pln"> todos</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ثانيًا، ارجع إلى متصفحك وافتح طرفية أدوات التطوير DevTools وانقر على زر تحديد الكل أو إلغاء تحديد الكل عدة مرات.
</p>

<p>
	ستلاحظ أنّ المصفوفة تُحدَّث بنجاح في كل مرة تضغط فيها على الزر، إذ تُبدَّل الخاصيات <code>completed</code> الخاصة بالكائنات <code>todo</code> بين القيمتين <code>true</code> و <code>false</code>، ولكن إطار Svelte ليس على علم بذلك، وهذا يعني أنه لن تكون تعليمة التفاعل مثل التعليمة <code>‎$: console.log('todos', todos)‎</code> مفيدةً جدًا في هذه الحالة، لذلك يجب فهم كيفية عمل التفاعل في إطار Svelte عند تحديث المصفوفات والكائنات.
</p>

<p>
	تستخدِم العديد من أطر عمل الويب تقنية نموذج DOM الافتراضي لتحديث الصفحة، إذ يُعَدّ DOM الافتراضي نسخةً في الذاكرة لمحتويات صفحة الويب، كما يحدّث إطار العمل هذا التمثيل الافتراضي الذي تجري مزامنته بعد ذلك مع نموذج DOM الحقيقي، وهذا أسرع بكثير من التحديث المباشر لنموذج DOM ويسمح لإطار العمل بتطبيق العديد من تقنيات التحسين، إذ تعيد هذه الأطر تشغيل كل شيفرة جافاسكربت افتراضيًا في كل تغيير لنموذج DOM الافتراضي، وتطبّق توابعًا مختلفةً لتخزين العمليات الحسابية باهظة الثمن مؤقتًا ولتحسين التنفيذ.
</p>

<p>
	لا يستخدِم إطار Svelte تمثيل نموذج DOM الافتراضي، وإنما يحلّل الشيفرة وينشئ شجرةً اعتماديةً، ثم ينشئ شيفرة جافاسكربت المطلوبة لتحديث أجزاء نموذج DOM التي تحتاج إلى تحديث فقط، إذ تنشئ هذه التقنية <a href="https://academy.hsoub.com/programming/javascript/%D9%86%D9%85%D8%B7-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%B4%D9%8A%D9%81%D8%B1%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r785/" rel="">شيفرة جافاسكربت</a> مثالية بأقل قدر من عمليات المعالجة إلى حد ما ولكن لذلك لا يخلو من بعض القيود.
</p>

<p>
	يتعذر على إطار Svelte في بعض الأحيان اكتشاف التغييرات التي تطرأ على المتغيرات المُراقَبة، وتذكَّر أنه يمكنك إخبار إطار Svelte بتغيّر متغير ما من خلال إسناد قيمة جديدة إليه، كما يجب أن يظهر اسم المتغير المُحدَّث على الجانب الأيسر من هذا الإسناد كما يلي على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_44" style=""><span class="kwd">const</span><span class="pln"> foo </span><span class="pun">=</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">foo
foo</span><span class="pun">.</span><span class="pln">bar </span><span class="pun">=</span><span class="pln"> </span><span class="str">'baz'</span></pre>

<p>
	لن يحدِّث إطار عمل Svelte مراجع الكائن <code>obj.foo.bar</code> إلّا إذا تتبّعتها باستخدام الإسناد <code>obj = obj</code>، إذ لا يمكن لإطار عمل Svelte تتبّع مراجع الكائنات، لذلك يجب إخباره صراحةً أنّ الكائن <code>obj</code> تغير باستخدام الإسناد.
</p>

<p>
	<strong>ملاحظة</strong>: إذا كان <code>foo</code> متغيرًا من المستوى الأعلى، فيمكنك بسهولة إخبار إطار Svelte بتحديث الكائن <code>obj</code> عندما يتغير المتغير <code>foo</code> باستخدام تعليمة التفاعل التالية: <code>‎$: foo, obj = obj</code>، وبالتالي يُعرَّف <code>foo</code> على أنه اعتمادية، وكلما تغير، سيعمل إطار عمل Svelte على تشغيل عملية الإسناد <code>obj = obj</code>.
</p>

<p>
	إذا شغلت ما يلي في الدالة <code>checkAllTodos()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_46" style=""><span class="pln">todos</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed </span><span class="pun">=</span><span class="pln"> completed</span><span class="pun">);</span></pre>

<p>
	لن يلحظ إطار Svelte تغيّر المصفوفة <code>todos</code> لأنه لا يعرف أننا نعدّلها عند تحديث المتغير <code>t</code> ضمن التابع <code>forEach()‎</code>، ويُعَدّ ذلك منطقيًا، إذ سيعرف إطار Svelte عمل التابع <code>forEach()‎</code> الداخلي إذا حدث عكس ذلك، لذا سيُطبَّق الأمر نفسه بالنسبة لأيّ تابع مرتبط بكائن أو مصفوفة، لكن هناك تقنيات مختلفة يمكننا تطبيقها لحل هذه المشكلة، وتتضمن جميعها إسناد قيمة جديدة للمتغير المُراقَب.
</p>

<p>
	يمكننا إخبار إطار عمل Svelte بتحديث المتغير باستخدام إسناد ذاتي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_48" style=""><span class="kwd">const</span><span class="pln"> checkAllTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">completed</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed </span><span class="pun">=</span><span class="pln"> completed</span><span class="pun">);</span><span class="pln">
  todos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تحل هذه الطريقة المشكلة، إذ سيرفع إطار Svelte رايةً تعبِّر عن تغيير المصفوفة <code>todos</code> ويزيل الإسناد الذاتي الذي يراه زائدًا، كما يمكن أن تبدو هذه الطريقة غريبةً، ولكنها تُعَدّ جيدةً ومختصَرةً.
</p>

<p>
	يمكننا الوصول أيضًا إلى المصفوفة <code>todos</code> باستخدام الفهرس كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_50" style=""><span class="kwd">const</span><span class="pln"> checkAllTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">completed</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">t</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> todos</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">completed </span><span class="pun">=</span><span class="pln"> completed</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تعمل الإسنادات إلى خاصيات المصفوفات والكائنات مثل <code>obj.foo += 1</code> أو <code>array[i] = x</code> بالطريقة نفسها للإسنادات إلى القيم نفسها، فإذا حلّل إطار عمل Svelte هذه الشيفرة، فيمكنه اكتشاف أنّ المصفوفة <code>todos</code> تُعدَّل.
</p>

<p>
	يوجد حل آخر هو إسناد مصفوفة جديدة إلى المصفوفة <code>todos</code>، إذ تحتوي هذه المصفوفة الجديدة على نسخة من جميع المهام مع تحديث الخاصية <code>completed</code> وفقًا لذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_52" style=""><span class="kwd">const</span><span class="pln"> checkAllTodos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">completed</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> </span><span class="pun">...</span><span class="pln">t</span><span class="pun">,</span><span class="pln"> completed </span><span class="pun">}));</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نستخدِم في هذه الحالة التابع <code>map()‎</code> الذي يعيد مصفوفةً جديدةً مع نتائج تنفيذ الدالة المتوفرة لكل عنصر، إذ تعيد الدالة نسخةً من كل مهمة باستخدام صيغة الانتشار Spread Syntax وتعيد كتابة خاصية القيمة <code>completed</code> وفقًا لذلك، وتتمثل فائدة هذا الحل في إعادة مصفوفة جديدة مع كائنات جديدة وتجنب تغيير المصفوفة <code>todos</code> الأصلية.
</p>

<p>
	<strong>ملاحظة</strong>: يتيح إطار Svelte تحديد خيارات مختلفة تؤثر على كيفية عمل المصرِّف Compiler، إذ يخبر الخيار <code>&lt;svelte:options immutable={true}/‎&gt;</code> المصرِّف بأنك تتعهد بعدم تغيير أيّ كائنات، مما يتيح له بأن يكون أقل تحفظًا بشأن التحقق من تغيير القيم وإنشاء شيفرة أبسط وأكثر فعالية.
</p>

<p>
	تتضمن كل هذه الحلول إسنادًا يكون فيه المتغير المحدَّث في الجانب الأيسر من المساواة، وستسمح جميعها لإطار Svelte بملاحظة تعديل المصفوفة <code>todos</code>، لذا اختر أحد هذه الحلول وحدّث الدالة <code>checkAllTodos()‎</code> كما هو مطلوب، ويجب الآن أن تكون قادرًا على تحديد جميع مهامك وإلغاء تحديدها دفعةً واحدةً.
</p>

<h2>
	الانتهاء من المكون MoreActions
</h2>

<p>
	سنضيف أحد تفاصيل إمكانية الاستخدام إلى مكوننا، إذ سنعطّل الأزرار في حالة عدم وجود مهام لمعالجتها من خلال استخدام المصفوفة <code>todos</code> بوصفها خاصيةً وضبط الخاصية <code>disabled</code> لكل زر وفقًا لذلك.
</p>

<p>
	أولًا، عدّل المكوِّن <code>MoreActions.svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_54" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createEventDispatcher </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte'</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> createEventDispatcher</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> todos

  </span><span class="kwd">let</span><span class="pln"> completed </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> checkAll </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    dispatch</span><span class="pun">(</span><span class="str">'checkAll'</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">)</span><span class="pln">
    completed </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">completed
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> removeCompleted </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> dispatch</span><span class="pun">(</span><span class="str">'removeCompleted'</span><span class="pun">)</span><span class="pln">

  $</span><span class="pun">:</span><span class="pln"> completedTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">).</span><span class="pln">length
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary"</span><span class="pln">
    </span><span class="atn">disabled</span><span class="pun">=</span><span class="atv">{todos.length</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> 0} </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{checkAll}</span><span class="tag">&gt;</span><span class="pln">{completed ? 'Check' : 'Uncheck'} all</span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary"</span><span class="pln">
    </span><span class="atn">disabled</span><span class="pun">=</span><span class="atv">{completedTodos</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> 0} </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{removeCompleted}</span><span class="tag">&gt;</span><span class="pln">Remove completed</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	صرّحنا عن متغير التفاعل <code>completedTodos</code> لتفعيل أو تعطيل زر "إزالة المهام المكتملة Remove Completed".
</p>

<p>
	لا تنسى تمرير الخاصية إلى المكوِّن <code>MoreActions</code> من المكوِّن <code>Todos.svelte</code> حيث يُستدعَى المكوِّن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_58" style=""><span class="tag">&lt;MoreActions</span><span class="pln"> {</span><span class="atn">todos</span><span class="pln">}
    </span><span class="atn">on:checkAll</span><span class="pun">=</span><span class="atv">{(e)</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> checkAllTodos(e.detail)}
    on:removeCompleted={removeCompletedTodos}
  /&gt;</span></pre>

<h2>
	التعامل مع نموذج DOM: التركيز على التفاصيل
</h2>

<p>
	أكملنا جميع الوظائف المطلوبة للتطبيق، وسنركِّز على بعض ميزات سهولة الوصول Accessibility التي ستحسّن إمكانية استخدام تطبيقنا لكل من مستخدمِي لوحة المفاتيح فقط وقارئات الشاشة، كما يواجه تطبيقنا حاليًا مشكلتين متعلقتين بسهولة وصول استخدام لوحة المفاتيح وتتضمن إدارة التركيز، لذا لنلقِ نظرةً على هذه المشاكل.
</p>

<h2>
	استكشاف مشاكل سهولة الوصول لمستخدمي لوحة المفاتيح في تطبيقنا
</h2>

<p>
	سيكتشف مستخدِمو لوحة المفاتيح حاليًا أنّ تدفق التركيز في تطبيقنا لا يمكن التنبؤ به أو غير مترابط، فإذا نقرت على حقل الإدخال في الجزء العلوي من تطبيقنا، فسترى حدًّا سميكًا ومتقطعًا حول هذا الحقل، إذ يُعَد هذا الحدّ المؤشر المرئي على أنّ المتصفح يركِّز حاليًا على هذا العنصر.
</p>

<p>
	إذا كنت من مستخدمِي الفأرة، فيمكن أن تتخطى هذه الإشارة المرئية، ولكن إذا أردت العمل باستخدام لوحة المفاتيح فقط، فمعرفة عنصر التحكم المُركَّز عليه أمرٌ بالغ الأهمية، إذ يخبرنا هذا التركيز أيّ عنصر تحكم سيتلقى ضغطات المفاتيح، فإذا ضغطت على مفتاح <code>Tab</code> بصورة متكررة، فسترى مؤشر التركيز المتقطع يتنقل بين جميع العناصر القابلة للتركيز على الصفحة، وإذا نقلت التركيز إلى زر "التعديل Edit" وضغطتَ على مفتاح <code>Enter</code>، فسيختفي التركيز فجأة دون إمكانية تحديد عنصر التحكم الذي سيتلقى ضغطات المفاتيح. إذا ضغطت على مفتاح <code>Escape</code> أو <code>Enter</code>، فلن يحدث شيء؛ أما إذا نقرت على زر "الإلغاء Cancel" أو "الحفظ Save"، فسيختفي التركيز مرةً أخرى، كما سيكون هذا السلوك محيرًا بالنسبة لمستخدِم يعمل باستخدام لوحة المفاتيح.
</p>

<p>
	كما نود إضافة بعض ميزات إمكانية الاستخدام مثل تعطيل زر "الحفظ Save" عندما تكون الحقول المطلوبة فارغةً، أو التركيز على بعض عناصر HTML أو التحديد التلقائي للمحتويات عند التركيز على حقل إدخال النص، كما يجب الوصول برمجيًا إلى عقد نموذج DOM لتشغيل دوال مثل الدالتين <code>focus()‎</code> و <code>select()‎</code> بهدف تطبيق جميع هذه الميزات، ويجب استخدام التابعين <code>addEventListener()‎</code> و <code>removeEventListener()‎</code> لتشغيل مهام محددة عندما يتلقى عنصر التحكم التركيز.
</p>

<p>
	تكمن المشكلة في أنّ جميع عقد نموذج DOM ينشئها إطار عمل Svelte ديناميكيًا في وقت التشغيل، لذا علينا الانتظار حتى إنشائها وإضافتها إلى نموذج DOM لاستخدامها، إذ يجب التعرف على دورة حياة المكونات لفهم متى يمكننا الوصول إليها.
</p>

<h2>
	إنشاء المكون NewTodo
</h2>

<p>
	أنشئ ملف مكوِّن جديد وعدّل الشيفرة لإصدار الحدث <code>addTodo</code> من خلال تمرير اسم المهمة الجديدة مع التفاصيل الإضافية كما يلي:
</p>

<p>
	أولًا، أنشئ ملفًا جديدًا بالاسم <code>components/NewTodo.svelte</code>.
</p>

<p>
	ضع بعد ذلك المحتويات التالية ضمن هذا الملف:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_60" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createEventDispatcher </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte'</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> createEventDispatcher</span><span class="pun">();</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addTodo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    dispatch</span><span class="pun">(</span><span class="str">'addTodo'</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">);</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> onCancel </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">

</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">on:submit</span><span class="pln">|</span><span class="atn">preventDefault</span><span class="pun">=</span><span class="atv">{addTodo}</span><span class="pln"> </span><span class="atn">on:keydown</span><span class="pun">=</span><span class="atv">{(e)</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> e.key === 'Escape' &amp;&amp; onCancel()}&gt;
  </span><span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"label-wrapper"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-0"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"label__lg"</span><span class="tag">&gt;</span><span class="pln">What needs to be done?</span><span class="tag">&lt;/label&gt;</span><span class="pln">
  </span><span class="tag">&lt;/h2&gt;</span><span class="pln">
  </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">bind:value</span><span class="pun">=</span><span class="atv">{name}</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-0"</span><span class="pln"> </span><span class="atn">autoComplete</span><span class="pun">=</span><span class="atv">"off"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"input input__lg"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">disabled</span><span class="pun">=</span><span class="atv">{!name}</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary btn__lg"</span><span class="tag">&gt;</span><span class="pln">Add</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;/form&gt;</span></pre>

<p>
	ربطنا هنا <a href="https://wiki.hsoub.com/HTML/input" rel="external">العنصر &lt;input&gt;</a> بالمتغير <code>name</code> باستخدام <code>bind:value={name}‎</code> وعطّلنا زر "الإضافة Add" عندما يكون حقل الإدخال فارغًا -أي لا يحتوي على محتوى نصي- باستخدام <code>disabled={!name}‎</code>، كما عالجنا استخدام مفتاح <code>Escape</code> باستخدام <code>on:keydown={(e) =&gt; e.key === 'Escape' &amp;&amp; onCancel()}‎</code>، إذ نشغّل التابع <code>onCancel()‎</code> الذي يمسح المتغير <code>name</code> في كل مرة نضغط فيها على مفتاح <code>Escape</code>.
</p>

<p>
	يجب الآن استيراد <code>import</code> المكوِّن <code>NewTodo</code> واستخدامه ضمن المكوِّن <code>Todos</code> وتحديث الدالة <code>addTodo()‎</code> للحصول على اسم المهمة الجديد، لذا أضف تعليمة الاستيراد التالية بعد تعليمات الاستيراد الأخرى الموجودة ضمن Todos.svelte:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_63" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">NewTodo</span><span class="pln"> from </span><span class="str">'./NewTodo.svelte'</span></pre>

<p>
	عدّل الدالة <code>addTodo()‎</code> بعد ذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_65" style=""><span class="kwd">function</span><span class="pln"> addTodo</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[...</span><span class="pln">todos</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> newTodoId</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تتلقى الدالة <code>addTodo()‎</code> الآن اسم المهمة الجديدة مباشرةً، لذلك لم نَعُد بحاجة المتغير <code>newTodoName</code> لإعطائه قيمة، إذ سيهتم المكوِّن <code>NewTodo</code> بذلك.
</p>

<p>
	<strong>ملاحظة</strong>: تُعَدّ الصيغة <code>{ name }</code> اختصارًا للصيغة <code>{ name: name }</code>، إذ يأتي هذا الاختصار من <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-javascript-r664/" rel="">لغة جافاسكربت</a> وليس له علاقة بإطار Svelte مع توفير بعض الإلهام للاختصارات الخاصة بإطار Svelte.
</p>

<p>
	أخيرًا، استبدل شيفرة HTML الخاصة بنموذج NewTodo باستدعاء المكوِّن <code>NewTodo</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_69" style=""><span class="com">&lt;!-- NewTodo --&gt;</span><span class="pln">
</span><span class="tag">&lt;NewTodo</span><span class="pln"> </span><span class="atn">on:addTodo</span><span class="pun">=</span><span class="atv">{(e)</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> addTodo(e.detail)} /&gt;</span></pre>

<h2>
	التعامل مع عقد نموذج DOM باستخدام الموجه bind:this={dom_node}‎
</h2>

<p>
	نريد الآن أن يعود التركيز إلى العنصر <code>&lt;input&gt;</code> الخاص بالمكون <code>NewTodo</code> في كل مرة يُضغَط فيها على زر "الإضافة Add"، لذا سنحتاج مرجعًا إلى عقدة نموذج DOM الخاصة بحقل الإدخال، إذ يوفر إطار عمل Svelte طريقةً لذلك باستخدام الموجِّه <code>bind:this={dom_node}‎</code>، كما يسند إطار Svelte مرجع عقدة DOM إلى متغير محدد بمجرد تثبيت المكوِّن وإنشاء عقدة DOM.
</p>

<p>
	لننشئ المتغير <code>nameEl</code> ونربطه بحقل الإدخال باستخدام <code>bind:this={nameEl}‎</code>، ثم سنستدعي التابع <code>nameEl.focus()‎</code> ضمن الدالة <code>addTodo()‎</code> لإعادة التركيز إلى العنصر <code>&lt;input&gt;</code> مرةً أخرى بعد إضافة المهام الجديدة، وسنطبّق الشيء نفسه عندما يضغط المستخدِم على مفتاح <code>Escape</code> باستخدام الدالة <code>onCancel()‎</code>.
</p>

<p>
	عدّل محتويات المكوِّن <code>NewTodo.svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_71" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createEventDispatcher </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte'</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> createEventDispatcher</span><span class="pun">();</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> nameEl</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫مرجع إلى عقدة حقل الإدخال name في نموذج DOM</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addTodo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    dispatch</span><span class="pun">(</span><span class="str">'addTodo'</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">);</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">
    nameEl</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ‫ركّز على حقل الإدخال name</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> onCancel </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">
    nameEl</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ‫ركّز على حقل الإدخال name</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">on:submit</span><span class="pln">|</span><span class="atn">preventDefault</span><span class="pun">=</span><span class="atv">{addTodo}</span><span class="pln"> </span><span class="atn">on:keydown</span><span class="pun">=</span><span class="atv">{(e)</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> e.key === 'Escape' &amp;&amp; onCancel()}&gt;
  </span><span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"label-wrapper"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-0"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"label__lg"</span><span class="tag">&gt;</span><span class="pln">What needs to be done?</span><span class="tag">&lt;/label&gt;</span><span class="pln">
  </span><span class="tag">&lt;/h2&gt;</span><span class="pln">
  </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">bind:value</span><span class="pun">=</span><span class="atv">{name}</span><span class="pln"> </span><span class="atn">bind:this</span><span class="pun">=</span><span class="atv">{nameEl}</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-0"</span><span class="pln"> </span><span class="atn">autoComplete</span><span class="pun">=</span><span class="atv">"off"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"input input__lg"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">disabled</span><span class="pun">=</span><span class="atv">{!name}</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary btn__lg"</span><span class="tag">&gt;</span><span class="pln">Add</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;/form&gt;</span></pre>

<p>
	جرِّب التطبيق واكتب اسم مهمة جديدة في حقل الإدخال <code>&lt;input&gt;</code> واضغط على المفتاح <code>tab</code> للتركيز على زر "الإضافة Add"، ثم اضغط على مفتاح <code>Enter</code> أو <code>Escape</code> لترى كيف يستعيد حقل الإدخال التركيز.
</p>

<h3>
	التركيز التلقائي على حقل الإدخال
</h3>

<p>
	الميزة التالية التي سنضيفها إلى المكوِّن <code>NewTodo</code> هي الخاصية <code>autofocus</code> التي ستسمح بتحديد أننا نريد التركيز على حقل الإدخال <code>&lt;input&gt;</code> في صفحة التحميل.
</p>

<p>
	محاولتنا الأولى هي كما يلي: لنحاول إضافة الخاصية <code>autofocus</code> واستدعاء التابع <code>nameEl.focus()‎</code> في كتلة القسم <code>&lt;script&gt;</code>، لذا عدِّل الجزء الأول من القسم <code>&lt;script&gt;</code> الخاص بالمكوِّن <code>NewTodo.svelte</code> (الأسطر الأربعة الأولى) لتبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_75" style=""><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createEventDispatcher </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte'</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> createEventDispatcher</span><span class="pun">();</span><span class="pln">

  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> autofocus </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> nameEl</span><span class="pun">;</span><span class="pln"> </span><span class="com">// مرجع إلى عقدة حقل الإدخال‫ name في نموذج DOM</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">autofocus</span><span class="pun">)</span><span class="pln"> nameEl</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span></pre>

<p>
	عُد الآن إلى المكوِّن <code>Todos</code> ومرّر الخاصية <code>autofocus</code> إلى استدعاء المكوِّن <code>&lt;NewTodo&gt;</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_78" style=""><span class="com">&lt;!-- NewTodo --&gt;</span><span class="pln">
</span><span class="tag">&lt;NewTodo</span><span class="pln"> </span><span class="atn">autofocus</span><span class="pln"> </span><span class="atn">on:addTodo</span><span class="pun">=</span><span class="atv">{(e)</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> addTodo(e.detail)} /&gt;</span></pre>

<p>
	إذا جربت تطبيقك، فسترى أنّ الصفحة فارغة حاليًا، وسترى في طرفية أدوات تطوير الويب خطأً بالشكل: <code>TypeError: nameEl is undefined</code>.
</p>

<h2>
	دورة حياة المكون والدالة onMount()‎
</h2>

<p>
	يشغّل إطار Svelte شيفرة التهيئة -أي قسم <code>&lt;script&gt;</code> الخاص بالمكون- عند إنشاء نسخة من هذا المكون، ولكن تكون جميع العقد التي يتألف منها المكوِّن غير مرتبطة بنموذج DOM في تلك اللحظة، وهي في الحقيقة غير موجودة أصلًا، كما يمكن أن تتساءل عن كيفية معرفة وقت إنشاء المكوِّن فعليًا وتثبيته على نموذج DOM، والإجابة هي أنه لكل مكوِّن دورة حياة تبدأ عند إنشائه وتنتهي عند تدميره، وهناك عدد من <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r781/" rel="">الدوال</a> التي تسمح بتشغيل الشيفرة في اللحظات المهمة خلال دورة الحياة هذه.
</p>

<p>
	الدالة التي ستستخدِمها بكثرة هي الدالة <code>onMount()‎</code> والتي تتيح تشغيل دالة رد نداء Callback بمجرد تثبيت المكوِّن على نموذج DOM، لذا لنجربها ونرى ما سيحدث للمتغير <code>nameEl</code>.
</p>

<p>
	أضِف أولًا السطر التالي في بداية القسم <code>&lt;script&gt;</code> الخاص بالمكوِّن <code>NewTodo.svelte</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_81" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> onMount </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte'</span><span class="pun">;</span></pre>

<p>
	وأضِف الأسطر التالية في نهايته:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_83" style=""><span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'initializing:'</span><span class="pun">,</span><span class="pln"> nameEl</span><span class="pun">);</span><span class="pln">
onMount</span><span class="pun">(</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'mounted:'</span><span class="pun">,</span><span class="pln"> nameEl</span><span class="pun">);</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	احذف الآن السطر <code>if (autofocus) nameEl.focus()‎</code> لتجنب الخطأ الذي رأيناه سابقًا.
</p>

<p>
	سيعمل التطبيق الآن مرةً أخرى، وسترى ما يلي في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_85" style=""><span class="pln">initializing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pln">
mounted</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">input id</span><span class="pun">=</span><span class="str">"todo-0"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"input input__lg"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln"> autocomplete</span><span class="pun">=</span><span class="str">"off"</span><span class="pun">&gt;</span></pre>

<p>
	يكون المتغير <code>nameEl</code> غير مُعرَّف أثناء تهيئة المكوِّن، وهو أمر منطقي لأن عقدة حقل الإدخال <code>&lt;input&gt;</code> غير موجودة حتى الآن، لذا أسند إطار عمل Svelte مرجع العقدة <code>&lt;input&gt;</code> في نموذج DOM إلى المتغير <code>nameEl</code> بفضل الموجّه <code>bind:this={nameEl}‎</code> بعد تثبيت المكوِّن.
</p>

<p>
	يمكنك تشغيل وظيفة التركيز التلقائي من خلال استبدال كتلة <code>onMount()‎</code> ضمن <code>console.log()‎</code> السابقة بما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_87" style=""><span class="pln">onMount</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> autofocus </span><span class="pun">&amp;&amp;</span><span class="pln"> nameEl</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">());</span><span class="pln">
 </span><span class="com">// ‫سنشغّل التابع nameEl.focus()‎ إذا كانت قيمة autofocus هي true</span></pre>

<p>
	انتقل إلى تطبيقك مرةً أخرى وسترى الآن تركيز حقل الإدخال <code>&lt;input&gt;</code> على صفحة التحميل.
</p>

<h2>
	انتظار تحديث نموذج DOM باستخدام الدالة tick()‎
</h2>

<p>
	سنهتم الآن بتفاصيل إدارة تركيز المكون <code>Todo</code>، إذ نريد أولًا أن يستلم تعديل حقل الإدخال <code>&lt;input&gt;</code> الخاص بالمكوِّن <code>Todo</code> التركيز عند الدخول في وضع التعديل من خلال الضغط على زر "التعديل Edit"، كما سننشئ المتغير <code>nameEl</code> ضمن المكوِّن <code>Todo.svelte</code> وسنستدعي التابع <code>nameEl.focus()‎</code> بعد ضبط المتغير <code>editing</code> على القيمة <code>true</code>.
</p>

<p>
	أولًا، افتح الملف <code>components/Todo.svelte</code> وأضِف التصريح عن المتغير <code>nameEl</code> التالي بعد التصريح عن المتغيرين <code>editing</code> و <code>name</code> مباشرةً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_89" style=""><span class="kwd">let</span><span class="pln"> nameEl</span><span class="pun">;</span><span class="pln">                              </span><span class="com">//  مرجع إلى عقدة حقل الإدخال‫ name في نموذج DOM</span></pre>

<p>
	ثانيًا، عدّل الدالة <code>onEdit()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_91" style=""><span class="kwd">function</span><span class="pln"> onEdit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  editing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">                        </span><span class="com">// الدخول في وضع التعديل</span><span class="pln">
  nameEl</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">                        </span><span class="com">// ‫ضبط التركيز على حقل الإدخال name</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أخيرًا، اربط المتغير <code>nameEl</code> بحقل الإدخال <code>&lt;input&gt;</code> من خلال تعديله كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_93" style=""><span class="pun">&lt;</span><span class="pln">input
  bind</span><span class="pun">:</span><span class="pln">value</span><span class="pun">={</span><span class="pln">name</span><span class="pun">}</span><span class="pln">
  bind</span><span class="pun">:</span><span class="kwd">this</span><span class="pun">={</span><span class="pln">nameEl</span><span class="pun">}</span><span class="pln">
  type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln">
  id</span><span class="pun">=</span><span class="str">"todo-{todo.id}"</span><span class="pln">
  autocomplete</span><span class="pun">=</span><span class="str">"off"</span><span class="pln">
  </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"todo-text"</span><span class="pln"> </span><span class="pun">/&gt;</span></pre>

<p>
	ولكن ستحصل على خطأ بالشكل: "TypeError: nameEl is undefined" في الطرفية عند الضغط على زر تعديل المهمة.
</p>

<p>
	لا يحدّث إطار عمل Svelte نموذج DOM مباشرةً عند تحديث حالة المكوِّن، وإنما ينتظر حتى المهمة السريعة microtask التالية لمعرفة ما إذا كانت هناك أيّ تغييرات أخرى يجب تطبيقها بما في ذلك التغييرات في المكونات الأخرى، مما يؤدي إلى تجنب العمل غير الضروري ويسمح للمتصفح بتجميع الأشياء بطريقة أكثر فعالية.
</p>

<p>
	لا يكون تعديل حقل الإدخال <code>&lt;input&gt;</code> مرئيًا في هذه الحالة لأنه غير موجود في نموذج DOM عندما يكون للمتغير <code>editing</code> القيمة <code>false</code>، لذا اضبط <code>editing = true</code> في الدالة <code>onEdit()‎</code> وحاول بعد ذلك مباشرةً الوصول إلى المتغير <code>nameEl</code> ونفّذ التابع <code>nameEl.focus()‎</code>، ولكن المشكلة هنا هي أنّ إطار عمل Svelte لم يحدّث نموذج DOM بعد.
</p>

<p>
	تتمثل إحدى طرق حل هذه المشكلة في استخدام التابع <code>setTimeout()‎</code> لتأخير استدعاء التابع <code>nameEl.focus()‎</code> حتى دورة الأحداث التالية وإعطاء <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">إطار عمل Svelte </a>الفرصة لتحديث نموذج DOM كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_95" style=""><span class="kwd">function</span><span class="pln"> onEdit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  editing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">                        </span><span class="com">// الدخول في وضع التعديل</span><span class="pln">
  setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> nameEl</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">(),</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">   </span><span class="com">// استدعاء غير متزامن لضبط التركيز على حقل الإدخال‫ name</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الحل السابق جيد، ولكنه غير مرتب إلى حد ما، إذ يوفر إطار Svelte طريقةً أفضل للتعامل مع هذه الحالات، حيث تعيد الدالة <code>tick()‎</code> وعدًا Promise يُحَل بمجرد تطبيق أيّ تغييرات على حالة مُعلَّقة في نموذج DOM، أو مباشرةً إذا لم تكن هناك تغييرات على حالة مُعلَّقة.
</p>

<p>
	استورد أولًا <code>tick</code> في بداية القسم <code>&lt;script&gt;</code> مع تعليمات الاستيراد الموجودة مسبقًا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_98" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> tick </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte'</span></pre>

<p>
	استدعِ بعد ذلك الدالة <code>tick()‎</code> مع المعامِل <code>await</code> من دالة غير متزامنة، وعدّل الدالة <code>onEdit()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_102" style=""><span class="kwd">async</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> onEdit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  editing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">                        </span><span class="com">// الدخول في وضع التعديل</span><span class="pln">
  </span><span class="kwd">await</span><span class="pln"> tick</span><span class="pun">();</span><span class="pln">
  nameEl</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا جربت التطبيق الآن، فسترى أنّ كل شيء يعمل كما هو متوقع.
</p>

<h2>
	إضافة وظائف إلى عناصر HTML باستخدام الموجه use:action
</h2>

<p>
	نريد بعد ذلك أن يحدّد حقل الإدخال <code>&lt;input&gt;</code> كل النص عند التركيز عليه، كما نريد تطوير ذلك بطريقة يمكن إعادة استخدامه بسهولة على أيّ عنصر <code>&lt;input&gt;</code> في HTML وتطبيقه بطريقة تصريحية، وسنستخدِم هذا المتطلب بوصفه سببًا لإظهار ميزة قوية جدًا يوفرها إطار Svelte لإضافة وظائف لعناصر HTML العادية، وهذه الميزة هي الإجراءات actions.
</p>

<p>
	يمكنك تحديد نص عقدة حقل إدخال في نموذج DOM من خلال استدعاء التابع <code>select()‎</code>، إذ يجب استخدام مستمع أحداث لاستدعاء هذه الدالة كلما انتقل التركيز إلى هذه العقدة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_104" style=""><span class="pln">node</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'focus'</span><span class="pun">,</span><span class="pln"> event </span><span class="pun">=&gt;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">select</span><span class="pun">())</span></pre>

<p>
	كما يجب استدعاء الدالة <code>removeEventListener()‎</code> عند تدمير العقدة لتجنب تسرّب الذاكرة Memory Leak.
</p>

<p>
	<strong>ملاحظة</strong>: كل ما سبق هو مجرد وظيفة قياسية من واجهة WebAPI دون وجود شيء خاص بإطار عمل Svelte.
</p>

<p>
	يمكن تحقيق كل ذلك في المكوِّن <code>Todo</code> كلما أضفنا أو أزلنا عنصر <code>&lt;input&gt;</code> من نموذج DOM، ولكن يجب أن نكون حريصين جدًا على إضافة مستمع الأحداث بعد إضافة العقدة إلى نموذج DOM وإزالة المستمع قبل إزالة العقدة من نموذج DOM. كما أنّ هذا الحل لن يكون قابلًا لإعادة الاستخدام بصورة كبيرة، وهنا يأتي دور إجراءات إطار Svelte التي تسمح بتشغيل دالة كلما أُضيف عنصر إلى نموذج DOM وبعد إزالته من نموذج DOM.
</p>

<p>
	سنعرّف دالة بالاسم <code>selectOnFocus()‎</code> تأخذ عقدة على أساس معامل لها، وستضيف هذه الدالة مستمع أحداث إلى تلك العقدة بحيث يُحدَّد النص كلما انتقل التركيز إليها، ثم ستعيد كائنًا مع الخاصية <code>destroy</code> التي سينفذها إطار Svelte بعد إزالة العقدة من نموذج DOM، وسنزيل هنا المستمع للتأكّد من أننا لا نترك أيّ تسرّب للذاكرة خلفنا.
</p>

<p>
	أولًا، لننشئ الدالة <code>selectOnFocus()‎</code>، لذا أضف ما يلي إلى أسفل القسم <code>&lt;script&gt;</code> الخاص بالمكوِّن <code>Todo.svelte</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_106" style=""><span class="kwd">function</span><span class="pln"> selectOnFocus</span><span class="pun">(</span><span class="pln">node</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">node </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">select </span><span class="pun">===</span><span class="pln"> </span><span class="str">'function'</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">           </span><span class="com">// ‫تأكّد من أن العقدة مُعرَّفة ولديها التابع select()‎</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> onFocus </span><span class="pun">=</span><span class="pln"> event </span><span class="pun">=&gt;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">select</span><span class="pun">();</span><span class="pln">                        </span><span class="com">// معالج الحدث</span><span class="pln">
    node</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'focus'</span><span class="pun">,</span><span class="pln"> onFocus</span><span class="pun">);</span><span class="pln">                      </span><span class="com">// ‫استدعِ التابع onFocus()‎ عندما ينتقل التركيز إلى العقدة</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      destroy</span><span class="pun">:</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">removeEventListener</span><span class="pun">(</span><span class="str">'focus'</span><span class="pun">,</span><span class="pln"> onFocus</span><span class="pun">)</span><span class="pln">   </span><span class="com">// ‫سيُنفَّذ هذا السطر عند إزالة العقدة من نموذج DOM</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يجب الآن إعلام حقل الإدخال <code>&lt;input&gt;</code> بأن يستخدِم هذه الدالة من خلال الموجّه <code>use:action</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_108" style=""><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">use:selectOnFocus</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	نطلب باستخدام هذا الموجّه من إطار Svelte تشغيل هذه الدالة وتمرير عقدة نموذج DOM الخاصة بحقل الإدخال <code>&lt;input&gt;</code> بوصفها معاملًا لها بمجرد تثبيت المكوِّن على نموذج DOM، وسيكون مسؤولًا عن تنفيذ الدالة <code>destroy</code> عند إزالة المكوِّن من نموذج DOM، وبالتالي يهتم Svelte بدورة حياة المكوِّن باستخدام الموجّه <code>use</code>، وسيكون العنصر <code>&lt;input&gt;</code> في حالتنا كما يلي:
</p>

<p>
	عدّل أول زوج تسمية أو عنوان/حقل إدخال label/input للمكوِّن ضمن قالب التعديل على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_110" style=""><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-label"</span><span class="tag">&gt;</span><span class="pln">New name for '{todo.name}'</span><span class="tag">&lt;/label&gt;</span><span class="pln">
</span><span class="tag">&lt;input</span><span class="pln">
  </span><span class="atn">bind:value</span><span class="pun">=</span><span class="atv">{name}</span><span class="pln">
  </span><span class="atn">bind:this</span><span class="pun">=</span><span class="atv">{nameEl}</span><span class="pln">
  </span><span class="atn">use:selectOnFocus</span><span class="pln">
  </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln">
  </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln">
  </span><span class="atn">autocomplete</span><span class="pun">=</span><span class="atv">"off"</span><span class="pln">
  </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-text"</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	انتقل إلى تطبيقك واضغط على زر تعديل المهام ثم اضغط على المفتاح <code>Tab</code> لإبعاد التركيز عن العنصر <code>&lt;input&gt;</code>، ثم انقر عليه وسترى تحديد نص حقل الإدخال بالكامل.
</p>

<h3>
	جعل الإجراء قابلا لإعادة الاستخدام
</h3>

<p>
	لنجعل الآن هذه الدالة قابلة لإعادة الاستخدام بين المكونات، إذ تُعَدّ الدالة <code>selectOnFocus()‎</code> مجرد دالة لا تعتمد على المكوِّن <code>Todo.svelte</code>، لذا يمكننا وضعها في ملف واستخدامها من هناك.
</p>

<p>
	أولًا، أنشئ ملفًا جديدًا بالاسم actions.js ضمن المجلد src.
</p>

<p>
	ثانيًا، ضع فيه المحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_112" style=""><span class="kwd">export</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> selectOnFocus</span><span class="pun">(</span><span class="pln">node</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">node </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">select </span><span class="pun">===</span><span class="pln"> </span><span class="str">'function'</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">               </span><span class="com">//  ‫تأكّد من أن العقدة مُعرَّفة ولديها التابع select()‎</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> onFocus </span><span class="pun">=</span><span class="pln"> event </span><span class="pun">=&gt;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">select</span><span class="pun">();</span><span class="pln">                        </span><span class="com">// معالج الحدث</span><span class="pln">
    node</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'focus'</span><span class="pun">,</span><span class="pln"> onFocus</span><span class="pun">);</span><span class="pln">                       </span><span class="com">// يُستدعى عند التركيز على القعدة</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      destroy</span><span class="pun">:</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">removeEventListener</span><span class="pun">(</span><span class="str">'focus'</span><span class="pun">,</span><span class="pln"> onFocus</span><span class="pun">)</span><span class="pln">   </span><span class="com">//  ‫سيُنفَّذ هذا السطر عند إزالة العقدة من نموذج DOM</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	استورده من داخل المكوِّن <code>Todo.svelte</code> من خلال إضافة تعليمة الاستيراد التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_114" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> selectOnFocus </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../actions.js'</span></pre>

<p>
	احذف تعريف الدالة <code>selectOnFocus()‎</code> من المكوِّن <code>Todo.svelte</code>، لأننا لم نعُد بحاجة إليها هناك.
</p>

<h3>
	إعادة استخدام الإجراء
</h3>

<p>
	لنستخدم الإجراء في المكوِّن <code>NewTodo.svelte</code> لإثبات إمكانية إعادة استخدامه.
</p>

<p>
	أولًا، استورد الدالة <code>selectOnFocus()‎</code> من الملف actions.js في الملف NewTodo.svelte كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_116" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> selectOnFocus </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../actions.js'</span><span class="pun">;</span></pre>

<p>
	ثانيًا، أضف الموجّه <code>use:selectOnFocus</code> إلى العنصر <code>&lt;input&gt;</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_118" style=""><span class="tag">&lt;input</span><span class="pln">
  </span><span class="atn">bind:value</span><span class="pun">=</span><span class="atv">{name}</span><span class="pln">
  </span><span class="atn">bind:this</span><span class="pun">=</span><span class="atv">{nameEl}</span><span class="pln">
  </span><span class="atn">use:selectOnFocus</span><span class="pln">
  </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln">
  </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-0"</span><span class="pln">
  </span><span class="atn">autocomplete</span><span class="pun">=</span><span class="atv">"off"</span><span class="pln">
  </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"input input__lg"</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	يمكننا إضافة وظائف لعناصر HTML العادية بطريقة قابلة لإعادة الاستخدام وتصريحية باستخدام بضعة أسطر من الشيفرة البرمجية، إذ يتطلب الأمر استيرادًا <code>import</code> وموجّهًا قصيرًا مثل الموجّه <code>use:selectOnFocus</code> الذي يوضِّح الغرض منه، ويمكننا تحقيق ذلك دون الحاجة إلى إنشاء عنصر مُغلِّف مخصَّص مثل <code>TextInput</code> أو <code>MyInput</code> أو ما شابه ذلك، كما يمكنك إضافة العديد من موجّهات <code>use:action</code> إلى عنصر ما.
</p>

<p>
	كما أنه ليس علينا أن نعاني باستخدام الدوال <code>onMount()‎</code> أو <code>onDestroy()‎</code> أو <code>tick()‎</code>، إذ يهتم الموجّه <code>use</code> بدورة حياة المكوِّن.
</p>

<h3>
	تحسينات الإجراءات الأخرى
</h3>

<p>
	كان علينا في القسم السابق أثناء العمل مع مكونات <code>Todo</code> التعاملَ مع الدوال <code>bind:this</code> و <code>tick()‎</code> و <code>async</code> للتركيز على حقل الإدخال <code>&lt;input&gt;</code> بمجرد إضافته إلى نموذج DOM.
</p>

<p>
	يمكننا تطبيق ذلك باستخدام الإجراءات كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_120" style=""><span class="kwd">const</span><span class="pln"> focusOnInit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">node</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> node </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">focus </span><span class="pun">===</span><span class="pln"> </span><span class="str">'function'</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span></pre>

<p>
	يجب بعد ذلك إضافة موجّه <code>use:‎</code> آخر في شيفرة HTML كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_122" style=""><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">bind:value</span><span class="pun">=</span><span class="atv">{name}</span><span class="pln"> </span><span class="atn">use:selectOnFocus</span><span class="pln"> </span><span class="atn">use:focusOnInit</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	يمكن الآن أن تكون الدالة <code>onEdit()‎</code> أبسط كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_124" style=""><span class="kwd">function</span><span class="pln"> onEdit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  editing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">                        </span><span class="com">// الدخول في وضع التعديل</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنعُد إلى المكوِّن <code>Todo.svelte</code> ونركّز على زر "التعديل Edit" بعد أن يضغط المستخدِم على زر "الحفظ Save" أو "الإلغاء Cancel".
</p>

<p>
	يمكننا محاولة إعادة استخدام الإجراء <code>focusOnInit</code> مرة أخرى من خلال إضافة الموجّه <code>use:focusOnInit</code> إلى زر "التعديل Edit"، لكننا سندخِل بذلك زلة برمجية، إذ سينتقل التركيز عند إضافة مهمة جديدة إلى زر "التعديل Edit" الخاص بالمهمة التي أُضيفت مؤخرًا بسبب تشغيل الإجراء <code>focusOnInit</code> عند إنشاء المكوِّن.
</p>

<p>
	لا نريد ذلك، وإنما نريد أن يستلم زر "التعديل Edit" التركيز فقط عندما يضغط المستخدِم على زر "الحفظ Save" أو "الإلغاء Cancel".
</p>

<p>
	لذا ارجع إلى الملف Todo.svelte، إذ سننشئ أولًا رايةً بالاسم <code>editButtonPressed</code> ونهيّئها بالقيمة <code>false</code>، لذا أضف ما يلي بعد تعريفات المتغيرات الأخرى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_126" style=""><span class="kwd">let</span><span class="pln"> editButtonPressed </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">           </span><span class="com">// تتبّع إذا ضُغِط على زر التعديل للتركيز عليه بعد الإلغاء أو الحفظ</span></pre>

<p>
	سنعدّل بعد ذلك وظيفة زر "التعديل Edit" لحفظ هذه الراية وإنشاء إجرائها الخاص، لذا عدّل الدالة <code>onEdit()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_128" style=""><span class="kwd">function</span><span class="pln"> onEdit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  editButtonPressed </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">              </span><span class="com">// سيؤدي ضغط المستخدم على زر التعديل إلى عودة التركيز إليه</span><span class="pln">
  editing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">                        </span><span class="com">// الدخول في وضع التعديل</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أضِف بعد ذلك تعريف الدالة <code>focusEditButton()‎</code> التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_130" style=""><span class="kwd">const</span><span class="pln"> focusEditButton </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">node</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> editButtonPressed </span><span class="pun">&amp;&amp;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span></pre>

<p>
	أخيرًا، استخدم الموجّه <code>use:focusEditButton</code> مع زر "التعديل Edit" كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_132" style=""><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{onEdit}</span><span class="pln"> </span><span class="atn">use:focusEditButton</span><span class="tag">&gt;</span><span class="pln">
  Edit</span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln"> {todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	جرّب تطبيقك مرةً أخرى، إذ يُنفَّذ الإجراء <code>focusEditButton</code> في هذه المرحلة في كل مرة يُضاف فيها زر "التعديل Edit" إلى نموذج DOM، ولكنه سيعطي التركيز فقط للزر إذا كانت قيمة الراية <code>editButtonPressed</code> هي <code>true</code>.
</p>

<p>
	<strong>ملاحظة</strong>: لم نتعمق كثيرًا في الإجراءات هنا، إذ يمكن أن تحتوي الإجراءات على معامِلات تفاعلية، ويتيح إطار Svelte اكتشاف متى يتغير أيّ من هذه المعامِلات لنتمكن من إضافة وظائف تتكامل جيدًا مع نظام التفاعل في إطار Svelte، كما تُعَدّ الإجراءات مفيدةً للتكامل بسلاسة مع المكتبات الخارجية.
</p>

<h2>
	ربط المكونات: الوصول إلى توابع ومتغيرات المكون باستخدام الموجه bind:this={component}‎
</h2>

<p>
	توجد مشكلة أخرى وهي أنه يتلاشى التركيز عندما يضغط المستخدِم على زر "الحذف Delete"، إذ تتضمن الميزة الأخيرة التي سنشرحها في هذا المقال ضبط التركيز على عنوان الحالة بعد حذف مهمة.
</p>

<p>
	اخترنا التركيز على عنوان الحالة بسبب حذف العنصر الذي جرى التركيز عليه، لذلك لا يوجد عنصر آخر واضح لتلقي التركيز، إذ يُعَدّ عنوان الحالة قريبًا من قائمة المهام، وهو طريقة مرئية لمعرفة إزالة المهمة بالإضافة إلى توضيح ما حدث لمستخدِمي قارئ الشاشة.
</p>

<p>
	أولًا، أنشئ ملفًا جديدًا بالاسم <code>components/TodosStatus.svelte</code>.
</p>

<p>
	ثانيًا، أضِف إليه المحتويات التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_134" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> todos</span><span class="pun">;</span><span class="pln">

  $</span><span class="pun">:</span><span class="pln"> totalTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
  $</span><span class="pun">:</span><span class="pln"> completedTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">todo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">).</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"list-heading"</span><span class="tag">&gt;</span><span class="pln">
  {completedTodos} out of {totalTodos} items completed
</span><span class="tag">&lt;/h2&gt;</span></pre>

<p>
	ثالثًا، استورد هذا الملف في بداية المكوِّن <code>Todos.svelte</code> من خلال إضافة تعليمة الاستيراد <code>import</code> التالية بعد تعليمات الاستيراد الأخرى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_136" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">TodosStatus</span><span class="pln"> from </span><span class="str">'./TodosStatus.svelte'</span><span class="pun">;</span></pre>

<p>
	رابعًا، استبدل عنوان الحالة <code>&lt;h2&gt;</code> ضمن الملف Todos.svelte باستدعاء المكوِّن <code>TodosStatus</code> من خلال تمرير <code>todos</code> إليه بوصفها خاصيةً كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_138" style=""><span class="tag">&lt;TodosStatus</span><span class="pln"> {</span><span class="atn">todos</span><span class="pln">} </span><span class="tag">/&gt;</span></pre>

<p>
	خامسًا، أزِل المتغيرين <code>totalTodos</code> و <code>completedTodos</code> من المكوِّن <code>Todos.svelte</code>، إذ ما عليك سوى إزالة السطرين <code>‎$: totalTodos = ...‎</code> و<code>‎$: completedTodos = ...‎</code> وإزالة المرجع إلى المتغير <code>totalTodos</code> عندما نحسب <code>newTodoId</code> واستخدم <code>todos.length</code> بدلًا من ذلك، أي استبدل الكتلة التي تبدأ بالسطر <code>let newTodoId</code> بما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_140" style=""><span class="pln">$</span><span class="pun">:</span><span class="pln"> newTodoId </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">length </span><span class="pun">?</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(...</span><span class="pln">todos</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span></pre>

<p>
	يعمل كل شيء كما هو متوقع، واستخرجنا للتو آخر جزء من شيفرة HTML إلى مكوِّنه الخاص.
</p>

<p>
	يجب الآن إيجاد طريقة للتركيز على تسمية الحالة <code>&lt;h2&gt;</code> بعد إزالة المهمة، إذ رأينا حتى الآن كيفية إرسال المعلومات إلى مكوِّن باستخدام الخاصيات Props، وكيف يمكن للمكوِّن التواصل مع المكوِّن الأب عن طريق إصدار أحداث أو استخدام ربط البيانات ثنائي الاتجاه، إذ يمكن للمكوِّن الابن الحصول على مرجع إلى العقدة <code>&lt;h2&gt;</code> باستخدام الموجّه <code>bind:this={dom_node}‎</code> ويمكن للمكونات الخارجية الوصول إليه باستخدام ربط البيانات ثنائي الاتجاه، لكن سيؤدي ذلك إلى كسر تغليف المكوِّن، لذلك نحن بحاجة إلى المكوِّن <code>TodosStatus</code> للوصول إلى تابع يمكن للمكوِّن الابن استدعاؤه للتركيز علي، إذ تُعَدّ حاجة المكوِّن لإمكانية وصول المستخدِم لبعض السلوك أو المعلومات أمرًا شائعًا جدًا، لذا لنرى كيفية تحقيق ذلك في إطار عمل Svelte.
</p>

<p>
	رأينا سابقًا أن إطار عمل Svelte يستخدِم التعليمة <code>export let varname = ...‎</code> للتصريح عن الخاصيات، ولكن إذا صدّرتَ ثابتًا <code>const</code> أو صنفًا <code>class</code> أودالةً <code>function</code> بدلًا من استخدام <code>let</code> لوحدها، فستكون للقراءة فقط خارج المكوِّن، وتُعَدّ تعابير الدوال خاصيات صالحةً.
</p>

<p>
	تُعَدّ التصريحات الثلاثة الأولى في المثال التالي خاصيات، والتصريحات الأخرى هي عبارة عن قيم مُصدَّرة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_142" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> bar </span><span class="pun">=</span><span class="pln"> </span><span class="str">"optional default initial value"</span><span class="pun">;</span><span class="pln">       </span><span class="com">// خاصية</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> baz </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pun">;</span><span class="pln">                              </span><span class="com">// خاصية</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> format </span><span class="pun">=</span><span class="pln"> n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">2</span><span class="pun">);</span><span class="pln">                   </span><span class="com">// خاصية</span><span class="pln">

  </span><span class="com">// these are readonly</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> thisIs </span><span class="pun">=</span><span class="pln"> </span><span class="str">"readonly"</span><span class="pun">;</span><span class="pln">                        </span><span class="com">// تصدير للقراءة فقط</span><span class="pln">

  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> greet</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                           </span><span class="com">// تصدير للقراءة فقط</span><span class="pln">
    alert</span><span class="pun">(`</span><span class="pln">hello $</span><span class="pun">{</span><span class="pln">name</span><span class="pun">}!`);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> greet </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(`</span><span class="pln">hello $</span><span class="pun">{</span><span class="pln">name</span><span class="pun">}!`);</span><span class="pln">  </span><span class="com">// تصدير للقراءة فقط</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	لننشئ تابعًا بالاسم <code>focus()‎</code> يركّز على العنوان <code>&lt;h2&gt;</code>، لذا سنحتاج إلى المتغير <code>headingEl</code> للاحتفاظ بالمرجع إلى عقدة DOM، ويجب ربطه بالعنصر <code>&lt;h2&gt;</code> باستخدام الموجّه ‎<code>‎bind:this={headingEl}‎‎</code>‎، إذ سيشغّل تابع التركيز فقط <code>headingEl.focus()‎</code>.
</p>

<p>
	أولًا، عدّل محتويات المكوِّن <code>TodosStatus.svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_144" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> todos</span><span class="pun">;</span><span class="pln">

  $</span><span class="pun">:</span><span class="pln"> totalTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
  $</span><span class="pun">:</span><span class="pln"> completedTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">todo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">).</span><span class="pln">length</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> headingEl</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> focus</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// shorter version: export const focus = () =&gt; headingEl.focus()</span><span class="pln">
    headingEl</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"list-heading"</span><span class="pln"> </span><span class="atn">bind:this</span><span class="pun">=</span><span class="atv">{headingEl}</span><span class="pln"> </span><span class="atn">tabindex</span><span class="pun">=</span><span class="atv">"-1"</span><span class="tag">&gt;</span><span class="pln">
  {completedTodos} out of {totalTodos} items completed
</span><span class="tag">&lt;/h2&gt;</span></pre>

<p>
	لاحظ أننا أضفنا السمة <code>tabindex</code> إلى العنوان <code>&lt;h2&gt;</code> للسماح للعنصر بتلقي التركيز برمجيًا، إذ يعطينا استخدام الموجِّه <code>bind:this={headingEl}‎</code> مرجعًا إلى عقدة DOM في المتغير <code>headingEl</code> كما رأينا سابقًا، كما نستخدم بعد ذلك التعليمة <code>export function focus()‎</code> لإمكانية الوصول إلى دالة تركّز على العنوان <code>&lt;h2&gt;</code>، كما يمكنك ربط نسخ المكوِّن باستخدام الموجِّه <code>bind:this={component}‎</code> مثل ربط عناصر DOM باستخدام الموجّه <code>bind:this={dom_node}‎</code>، لذا تحصل على مرجع لعقدة DOM عند استخدام الموجِّه <code>bind:this</code> مع عنصر HTML، وتحصل على مرجع إلى نسخة من هذا المكوِّن عندما تفعل ذلك مع مكوِّن Svelte.
</p>

<p>
	ثانيًا، سننشئ أولًا المتغير <code>todosStatus</code> في <code>Todos.svelte</code> للربط بنسخة من المكوِّن <code>Todos.svelte</code>، لذا أضف السطر التالي بعد تعليمات الاستيراد الموجودة مسبقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_146" style=""><span class="kwd">let</span><span class="pln"> todosStatus</span><span class="pun">;</span><span class="pln">                   </span><span class="com">// ‫مرجع إلى نسخة من المكون TodosStatus</span></pre>

<p>
	ثالثًا، أضِف بعد ذلك الموجّه <code>bind:this={todosStatus}‎</code> إلى الاستدعاء كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4408_148" style=""><span class="com">&lt;!-- TodosStatus --&gt;</span><span class="pln">
</span><span class="tag">&lt;TodosStatus</span><span class="pln"> </span><span class="atn">bind:this</span><span class="pun">=</span><span class="atv">{todosStatus}</span><span class="pln"> {</span><span class="atn">todos</span><span class="pln">} </span><span class="tag">/&gt;</span></pre>

<p>
	رابعًا، يمكننا الآن استدعاء التابع <code>focus()‎</code> المُصدَّر من التابع <code>removeTodo()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_150" style=""><span class="kwd">function</span><span class="pln"> removeTodo</span><span class="pun">(</span><span class="pln">todo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">id</span><span class="pun">);</span><span class="pln">
  todosStatus</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">             </span><span class="com">// ركّز على عنوان الحالة</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	خامسًا، ارجع إلى تطبيقك، فإذا حذفت أيّ مهمة الآن، فسينتقل التركيز إلى عنوان الحالة، وهذا مفيد لتسليط الضوء على التغيير في عدد المهام لكل من المستخدِمين المبصرين ومستخدِمي قارئات الشاشة.
</p>

<p>
	<strong>ملاحظة</strong>: يمكن أن تتساءل عن سبب حاجتنا للتصريح عن متغير جديد لربط المكون بالرغم من أنه يمكننا فقط استدعاء التابع <code>TodosStatus.focus()‎</code>، إذ يمكن أن يكون لديك العديد من نسخ المكوِّن <code>TodosStatus</code> النشطة، لذلك تحتاج لطريقة للرجوع إلى كل نسخة معينة، وبالتالي يجب تحديد متغير لربط كل نسخة محددة به.
</p>

<p>
	يمكنك الوصول إلى نسختك من مستودعنا على النحو التالي لمعرفة حالة الشيفرة كما يجب أن تكون في نهاية هذا المقال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_152" style=""><span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">06</span><span class="pun">-</span><span class="pln">stores</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4408_154" style=""><span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">06</span><span class="pun">-</span><span class="pln">stores</span></pre>

<p>
	تذكَّر تشغيل الأمر <code>npm install &amp;&amp; npm run dev</code> لبدء تشغيل تطبيقك في وضع التطوير، فإذا أردت متابعتنا، فابدأ بكتابة الشيفرة باستخدام الأداة REPL من <a href="https://svelte.dev/repl/d1fa84a5a4494366b179c87395940039?version=3.23.2" rel="external nofollow">موقع svelte.dev</a>.
</p>

<h2>
	الخلاصة
</h2>

<p>
	انتهينا في هذا المقال من إضافة جميع الوظائف المطلوبة إلى تطبيقنا، بالإضافة إلى اهتمامنا بعدد من مشاكل سهولة الوصول وسهولة الاستخدام، وانتهينا من تقسيم تطبيقنا إلى مكونات يمكن إدارتها مع إعطاء كل منها مسؤولية فريدة، كما رأينا بعض تقنيات إطار عمل Svelte المتقدمة مثل:
</p>

<ul>
	<li>
		التعامل مع اكتشاف التفاعل عند تحديث العناصر والمصفوفات.
	</li>
	<li>
		العمل مع عقد DOM باستخدام الموجّه <code>bind:this={dom_node}‎</code> (ربط عناصر DOM).
	</li>
	<li>
		استخدام الدالة <code>onMount()‎</code> الخاصة بدورة حياة المكوِّن.
	</li>
	<li>
		إجبار إطار عمل Svelte على حل تغييرات الحالة المُعلَّقة باستخدام الدالة <code>tick()‎</code>.
	</li>
	<li>
		إضافة وظائف لعناصر HTML بطريقة تصريحية وقابلة لإعادة الاستخدام باستخدام الموجّه <code>use:action</code>.
	</li>
	<li>
		الوصول إلى توابع المكونات باستخدام الموجّه <code>bind:this={component}‎</code> (ربط المكونات).
	</li>
</ul>

<p>
	سنرى في المقال التالي كيفية استخدام المخازن Stores للتواصل بين المكونات وإضافة الحركة إلى المكونات.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_reactivity_lifecycle_accessibility" rel="external nofollow">Advanced Svelte: Reactivity, lifecycle, accessibility</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">بدء استخدام إطار العمل Svelte لبناء تطبيقات ويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1811/" rel="">إنشاء تطبيق قائمة مهام باستعمال إطار عمل Svelte</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1822/" rel="">التعامل مع المتغيرات والخاصيات في إطار عمل Svelte</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%82%D8%B3%D9%8A%D9%85-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-svelte-%D8%A5%D9%84%D9%89-%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-r1823/" rel="">تقسيم تطبيق Svelte إلى مكونات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1863</guid><pubDate>Thu, 19 Jan 2023 18:00:00 +0000</pubDate></item><item><title>&#x62A;&#x642;&#x633;&#x64A;&#x645; &#x62A;&#x637;&#x628;&#x64A;&#x642; Svelte &#x625;&#x644;&#x649; &#x645;&#x643;&#x648;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D9%82%D8%B3%D9%8A%D9%85-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-svelte-%D8%A5%D9%84%D9%89-%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-r1823/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_12/63986bec3c45b_--Svelte--.png.8a8ad13e4f1eebec8716d5d1843650b9.png" /></p>

<p>
	بدأنا في <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1822/" rel="">مقال التعامل مع المتغيرات والخاصيات</a> بتطوير تطبيق قائمة المهام، والهدف الأساسي من هذا المقال هو تعلّم كيفية تقسيم تطبيقنا إلى مكونات يمكن إدارتها ومشاركة المعلومات فيما بينها. سنقسّم تطبيقنا إلى مكونات، ثم سنضيف مزيدًا من الوظائف للسماح للمستخدمين بتحديث المكونات الحالية.
</p>

<ul>
<li>
		<strong>المتطلبات الأساسية</strong>: يوصَى على الأقل بأن تكون على دراية بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة باستخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471" rel="">سطر الأوامر أو الطرفية</a>، وستحتاج طرفية مثبَّت عليها node و npm لتصريف وبناء تطبيقك.
	</li>
	<li>
		<strong>الهدف</strong>: تعلم كيفية تقسيم تطبيقنا إلى مكونات ومشاركة المعلومات فيما بينها.
	</li>
</ul>
<p>
	يمكنك متابعة كتابة شيفرتك معنا، لذلك انسخ أولًا مستودع github -إذا لم تفعل ذلك مسبقًا- باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_9" style="">
<span class="pln">git clone https</span><span class="pun">:</span><span class="com">//github.com/opensas/mdn-svelte-tutorial.git</span></pre>

<p>
	ثم يمكنك الوصول إلى حالة التطبيق الحالية من خلال تشغيل الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_12" style="">
<span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">04</span><span class="pun">-</span><span class="pln">componentizing</span><span class="pun">-</span><span class="pln">our</span><span class="pun">-</span><span class="pln">app</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_14" style="">
<span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">04</span><span class="pun">-</span><span class="pln">componentizing</span><span class="pun">-</span><span class="pln">our</span><span class="pun">-</span><span class="pln">app</span></pre>

<p>
	تذكَّر تشغيل الأمر <code>npm install &amp;&amp; npm run dev</code> لبدء تشغيل تطبيقك في وضع التطوير، وإذا أردت متابعتنا فابدأ بكتابة الشيفرة باستخدام <a href="https://svelte.dev/repl/99b9eb228b404a2f8c8959b22c0a40d3?version=3.23.2" rel="external nofollow">الأداة REPL</a>.
</p>

<h2>
	تقسيم التطبيق إلى مكونات
</h2>

<p>
	يتكون التطبيق في <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">إطار عمل Svelte</a> من مكوِّن واحد أو من مكونات متعددة، ويُعَدّ المكوِّن كتلةً من الشيفرة البرمجية القابلة لإعادة الاستخدام والمستقلة ذاتيًا والتي تغلّف شيفرة <a href="https://academy.hsoub.com/programming/html/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-html-r1687/" rel="">HTML</a> و <a href="https://academy.hsoub.com/programming/css/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-css-r1688/" rel="">CSS</a> و<a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1689/" rel="">جافاسكربت</a> المرتبطة مع بعضها البعض والمكتوبة في ملف <code>‎.svelte</code>، كما يمكن أن تكون المكونات كبيرةً أو صغيرةً، لكنها تكون عادةً محدَّدةً بوضوح، فالمكونات الأكثر فاعليةً هي المكونات التي تخدم غرضًا واحدًا واضحًا.
</p>

<p>
	من فوائد تحديد المكونات هو قابلية هذه المكونات للموازنة مع أفضل الممارسات العامة بهدف تنظيم شيفرتك البرمجية ضمن أجزاء يمكن إدارتها، مما يساعدك على فهم كيفية ارتباطها ببعضها البعض ويعزِّز إعادة الاستخدام ويجعل شيفرتك البرمجية أسهل للتفكير بها وصيانتها وتوسيعها.
</p>

<p>
	لا توجد قواعد صارمة لتقسيم المكونات، لذا يفضِّل بعض الأشخاص اتباع نهج بسيط يتمثل بالنظر إلى شيفرة HTML ثم رسم مربعات حول كل مكوِّن ومكوِّن فرعي يبدو أنّ له شيفرته الخاصة، في حين يطبق أشخاص آخرون الأساليب نفسها المُستخدَمة لتحديد ما إذا كان يجب إنشاء دالة أو كائن جديد، وأحد هذه الأساليب هو مبدأ المسؤولية الفردية، أي يجب أن يطبّق المكون شيئًا واحدًا فقط بصورة مثالية، ثم يمكننا تقسيمه إلى مكونات فرعية أصغر إذا لزم الأمر، كما يجب أن يكمل هذا النهجان بعضهما البعض لمساعدتك على تحديد كيفية تنظيم مكوناتك بطريقة أفضل.
</p>

<p>
	سنقسم تطبيقنا إلى المكونات التالية:
</p>

<ul>
<li>
		<code>Alert.svelte</code>: مربع إشعارات عام لإرسال الإجراءات التي حدثت.
	</li>
	<li>
		<code>NewTodo.svelte</code>: حقل إدخال النص والزر الذي يسمح بإدخال عنصر مهام جديد.
	</li>
	<li>
		<code>FilterButton.svelte</code>: أزرار "كل المهام All" و"المهام النشطة Active" و"المهام المكتملة Completed" التي تسمح بتطبيق المرشّحات Filters على عناصر المهام المعروضة.
	</li>
	<li>
		<code>TodosStatus.svelte</code>: العنوان الذي يعرض العبارة "x out of y items completed" التي تمثّل عدد المهام المكتملة.
	</li>
	<li>
		<code>Todo.svelte</code>: عنصر مهام مفرد، إذ سيُعرَض كل عنصر مهمة مرئي في نسخة منفصلة من هذا المكوِّن.
	</li>
	<li>
		<code>MoreActions.svelte</code>: الزرّان "تحديد الكل Check All" و"احذف المهام المكتملة Remove Completed" الموجودان أسفل واجهة المستخدِم، ويسمحان بتنفيذ مجموعة إجراءات على عناصر المهام.
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="113771" href="https://academy.hsoub.com/uploads/monthly_2022_12/01_todo-components.png.6dd291d8ecca9ae59bed9654cab13f20.png" rel=""><img alt="تقسيم التطبيق إلى مكونات" class="ipsImage ipsImage_thumbnailed" data-fileid="113771" data-unique="t681thnuy" src="https://academy.hsoub.com/uploads/monthly_2022_12/01_todo-components.thumb.png.d8f6674a9481bfbc439b6c5e630b363a.png" style="width: 600px; height: auto;"></a>
</p>

<p>
	سنركز في هذا المقال على إنشاء المكونين <code>FilterButton</code> و <code>Todo</code> وسنشرح المكونات الأخرى في المقالات القادمة.
</p>

<p>
	<strong>ملاحظة</strong>: سنتعلم أيضًا في عملية إنشاء أول مكونين تقنيات مختلفة لتواصل المكونات مع بعضها بعضًا، وإيجابيات وسلبيات كل من هذه التقنيات.
</p>

<h2>
	استخراج مكون الترشيح
</h2>

<p>
	سننشئ أولًا المكون <code>FilterButton.svelte</code> باتباع الخطوات التالية:
</p>

<p>
	أولًا، أنشئ ملفًا جديدًا components/FilterButton.svelte.
</p>

<p>
	ثانيًا، سنصرّح عن الخاصية <code>filter</code> في هذا الملف ثم سننسخ شيفرة HTML المتعلقة به من الملف Todos.svelte، لذا أضِف المحتوى التالي إلى هذا الملف:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_23" style="">
<span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> let filter </span><span class="pun">=</span><span class="pln"> </span><span class="str">'all'</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"filters btn-group stack-exception"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn toggle-btn"</span><span class="pln"> </span><span class="atn">class:btn__primary</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'all'</span><span class="pln">} </span><span class="atn">aria-pressed</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'all'</span><span class="pln">} </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()=</span><span class="tag">&gt;</span><span class="pln"> filter = 'all'} &gt;
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Show</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span&gt;</span><span class="pln">All</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">tasks</span><span class="tag">&lt;/span&gt;</span><span class="pln">
  </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn toggle-btn"</span><span class="pln"> </span><span class="atn">class:btn__primary</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'active'</span><span class="pln">} </span><span class="atn">aria-pressed</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'active'</span><span class="pln">} </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()=</span><span class="tag">&gt;</span><span class="pln"> filter = 'active'} &gt;
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Show</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span&gt;</span><span class="pln">Active</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">tasks</span><span class="tag">&lt;/span&gt;</span><span class="pln">
  </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn toggle-btn"</span><span class="pln"> </span><span class="atn">class:btn__primary</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'completed'</span><span class="pln">} </span><span class="atn">aria-pressed</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'completed'</span><span class="pln">} </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()=</span><span class="tag">&gt;</span><span class="pln"> filter = 'completed'} &gt;
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Show</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span&gt;</span><span class="pln">Completed</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">tasks</span><span class="tag">&lt;/span&gt;</span><span class="pln">
  </span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	ثالثًا، ارجع إلى المكوِّن <code>Todos.svelte</code>، حيث نريد الاستفادة من المكوِّن <code>FilterButton</code>، إذ يجب استيراده أولًا، لذا أضِف السطر التالي قبل القسم <code>&lt;script&gt;</code> في المكوِّن <code>Todos.svelte</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_25" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">FilterButton</span><span class="pln"> from </span><span class="str">'./FilterButton.svelte'</span></pre>

<p>
	رابعًا، استبدل الآن <a href="https://wiki.hsoub.com/HTML/div" rel="external">العنصر &lt;div&gt;</a> الذي يملك اسم الصنف <code>filters</code> باستدعاء المكون <code>FilterButton</code> الذي يأخذ المرشح الحالي بوصفه خاصيةً كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_27" style="">
<span class="tag">&lt;FilterButton</span><span class="pln"> {</span><span class="atn">filter</span><span class="pln">} </span><span class="tag">/&gt;</span></pre>

<p>
	<strong>ملاحظة</strong>: تذكَّر أنه إذا تطابق اسم سمة في لغة HTML مع اسم المتغير، فيمكن استبدالهما بالشكل <code>{variable}</code>، لذا يمكننا استبدال <code>&lt;FilterButton filter={filter} /‎&gt;</code> بالشكل <code>&lt;FilterButton {filter} /‎&gt;</code>.
</p>

<p>
	لنجرب التطبيق الآن، حيث ستلاحظ أنه إذا نقرت على أزرار الترشيح، فستُحدَّد هذه الأزرار وسيُحدَّث التنسيق بطريقة مناسبة، ولكن لدينا مشكلة وهي عدم ترشيح المهام، وسبب هذه المشكلة هو انتقال المتغير <code>filter</code> من المكوِّن <code>Todos</code> إلى المكوِّن <code>FilterButton</code> عبر الخاصية، ولكن لا تنتقل التغييرات التي تحدث في المكوِّن <code>FilterButton</code> مرةً أخرى إلى المكوِّن الأب، إذ يكون ارتباط البيانات أحادي الاتجاه افتراضيًا.
</p>

<h2>
	مشاركة البيانات بين المكونات: تمرير المعالج بوصفه خاصية
</h2>

<p>
	تتمثل إحدى طرق السماح للمكونات الأبناء بإعلام المكونات الآباء بأيّ تغييرات في تمرير المعالج بوصفه خاصيةً Prop، حيث سينفّذ المكوِّن الابن المعالج، ويمرّر المعلومات المطلوبة بوصفها معاملًا وسيعدّل المعالج حالة المكوِّن الأب، كما سيتلقّى المكوِّن <code>FilterButton</code> في حالتنا المعالج <code>onclick</code> من المكوِّن الأب، فإذا نقر المستخدِم على أيّ زر ترشيح، فسيستدعي المكونُ الابن المعالجَ <code>onclick</code> ويمرّر المرشّح المحدد على أساس معامل إلى المكوِّن الأب.
</p>

<p>
	سنصرّح فقط عن الخاصية <code>onclick</code> التي تُسنَد إلى معالِج وهمي لمنع الأخطاء كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_31" style="">
<span class="kwd">export</span><span class="pln"> let onclick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">clicked</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{}</span></pre>

<p>
	وسنصرّح عن التعليمة التفاعلية <code>‎$: onclick(filter)‎</code> لاستدعاء المعالِج <code>onclick</code> كلما جرى تحديث المتغير <code>filter</code>.
</p>

<p>
	أولًا، يجب أن يبدو القسم <code>&lt;script&gt;</code> الخاص بالمكوِّن <code>FilterButton</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_33" style="">
<span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> let filter </span><span class="pun">=</span><span class="pln"> </span><span class="str">'all'</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> let onclick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">clicked</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
  $</span><span class="pun">:</span><span class="pln"> onclick</span><span class="pun">(</span><span class="pln">filter</span><span class="pun">)</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	إذا استدعينا المكوِّن <code>FilterButton</code> ضمن المكوِّن <code>Todos.svelte</code> الآن، فيجب تحديد المعالج، لذا عدّله إلى ما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_35" style="">
<span class="tag">&lt;FilterButton</span><span class="pln"> {</span><span class="atn">filter</span><span class="pln">} </span><span class="atn">onclick</span><span class="pun">={</span><span class="pln"> (</span><span class="atn">clicked</span><span class="pln">) </span><span class="tag">=&gt;</span><span class="pln"> filter = clicked }/&gt;</span></pre>

<p>
	إذا نقرت على أيّ زر ترشيح، فسنعدّل المتغير <code>filter</code> باستخدام المرشّح الجديد وسيعمل المكوِّن <code>FilterButton</code> مرةً أخرى.
</p>

<h2>
	طريقة أسهل لربط البيانات ثنائي الاتجاه باستخدام الموجه bind
</h2>

<p>
	أدركنا في المثال السابق أنّ المكوِّن <code>FilterButton</code> لم يعمل، لأنّ حالة التطبيق تنتقل من المكوِّن الأب إلى المكوِّن الابن من خلال الخاصية <code>filter</code>، ولكنها لا ترجع مرةً أخرى من المكوِّن الابن إلى المكوِّن الأب، لذلك أضفنا الخاصية <code>onclick</code> للسماح للمكوِّن الابن بإرسال قيمة الخاصية <code>filter</code> الجديدة إلى المكوِّن الأب.
</p>

<p>
	يعمل التطبيق جيدًا، ولكن يوفر إطار عمل Svelte طريقةً سهلةً ومباشرةً لتحقيق ربط البيانات ثنائي الاتجاه، إذ تتدفق البيانات عادةً من المكوِّن الأب إلى المكوِّن الابن باستخدام الخاصيات، وإذا أردنا أن تتدفق في الاتجاه الآخر من المكوِّن الابن إلى المكوِّن الأب، فيمكننا استخدام الموجّه <code>bind:‎</code>.
</p>

<p>
	سنخبر إطار عمل Svelte باستخدام الموجّه <code>bind</code> أنّ أيّ تغييرات تجرَى على الخاصية <code>filter</code> في المكوِّن <code>FilterButton</code> يجب أن تنتشر إلى المكوِّن الأب <code>Todos</code>، أي أننا سنربط قيمة المتغير <code>filter</code> في المكوِّن الأب بقيمته في المكوِّن الابن.
</p>

<p>
	أولًا، عدّل استدعاء المكوِّن <code>FilterButton</code> في <code>Todos.svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_37" style="">
<span class="tag">&lt;FilterButton</span><span class="pln"> </span><span class="atn">bind:filter</span><span class="pun">=</span><span class="atv">{filter}</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	يوفِّر إطار عمل Svelte اختصارًا، إذ تعادل التعليمةُ <code>bind:value={value}‎</code> التعليمةَ <code>bind:value</code>، لذلك يمكنك في المثال السابق كتابة <code>&lt;FilterButton bind:filter /‎&gt;</code> فقط.
</p>

<p>
	ثانيًا، يمكن للمكوِّن الابن الآن تعديل قيمة المتغير <code>filter</code> الخاص بالمكون الأب، لذلك لم نعد بحاجة إلى الخاصية <code>onclick</code>، لذا عدّل القسم <code>&lt;script&gt;</code> الخاص بالمكوِّن <code>FilterButton</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_39" style="">
<span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> let filter </span><span class="pun">=</span><span class="pln"> </span><span class="str">'all'</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	ثالثًا، جرب تطبيقك مرةً أخرى، وستظل ترى أن المرشّحات تعمل بصورة صحيحة.
</p>

<h2>
	إنشاء المكون Todo
</h2>

<p>
	سننشئ الآن المكون <code>Todo</code> لتغليف كل مهمة بما في ذلك مربع الاختيار وشيفرة التعديل لتتمكّن من تعديل مهمة موجودة مسبقًا، وسيتلقى المكوِّن <code>Todo</code> الكائن <code>todo</code> بوصفه خاصيةً، لذا لنصرّح عن الخاصية <code>todo</code> ولننقل الشيفرة البرمجية من المكوِّن <code>Todos</code>، كما سنستبدل حاليًا استدعاء <code>removeTodo</code> باستدعاء <code>alert</code> وسنضيف هذه الوظيفة مرةً أخرى في وقت لاحق.
</p>

<p>
	أنشئ ملف مكوِّن جديد <code>components/Todo.svelte</code>، وضَع بعد ذلك المحتويات التالية ضمن هذا الملف:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_41" style="">
<span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> let todo
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-small"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"c-cb"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln">
      </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> todo.completed = !todo.completed}
      checked={todo.completed}
    /&gt;
    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-label"</span><span class="tag">&gt;</span><span class="pln">{todo.name}</span><span class="tag">&lt;/label&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn"</span><span class="tag">&gt;</span><span class="pln">
      Edit </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">{todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__danger"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> alert('not implemented')}&gt;
      Delete </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">{todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	يجب الآن استيراد المكوِّن <code>Todo</code> إلى <code>Todos.svelte</code>، لذا انتقل إلى هذا الملف الآن وأضف تعليمة الاستيراد <code>import</code> التالية بعد تعليمة الاستيراد الموجودة مسبقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_43" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Todo</span><span class="pln"> from </span><span class="str">'./Todo.svelte'</span></pre>

<p>
	يجب بعد ذلك تحديث كتلة <code>{‎#each}</code> لتضمين المكوِّن <code>&lt;Todo&gt;</code> لكل مهمة بدلًا من الشيفرة المنقولة إلى <code>Todo.svelte</code>، ويجب تمرير كائن <code>todo</code> الحالي إلى المكوِّن بوصفه خاصيةً، لذا عدّل كتلة <code>{‎#each}</code> ضمن المكوِّن <code>Todos.svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_45" style="">
<span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">role</span><span class="pun">=</span><span class="atv">"list"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-list stack-large"</span><span class="pln"> </span><span class="atn">aria-labelledby</span><span class="pun">=</span><span class="atv">"list-heading"</span><span class="tag">&gt;</span><span class="pln">
  {#each filterTodos(filter, todos) as todo (todo.id)}
    </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;Todo</span><span class="pln"> {</span><span class="atn">todo</span><span class="pln">} </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;/li&gt;</span><span class="pln">
  {:else}
    </span><span class="tag">&lt;li&gt;</span><span class="pln">Nothing to do here!</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  {/each}
</span><span class="tag">&lt;/ul&gt;</span></pre>

<p>
	تُعرَض قائمة المهام على الصفحة، ويجب أن تعمل مربعات الاختيار (حاول تحديد أو إلغاء تحديد مربعات الاختيار، ثم لاحظ أنّ المرشحات لا تزال تعمل كما هو متوقع)، ولكن لن يُحدَّث عنوان الحالة "x out of y items completed" وفقًا لذلك لأن المكوِّن <code>Todo</code> يتلقى المهام باستخدام الخاصية، لكنه لا يرسل أيّ معلومات إلى المكوِّن الأب، وسنصلح ذلك لاحقًا.
</p>

<h2>
	مشاركة البيانات بين المكونات: نمط الخاصيات للأسفل Props-down والأحداث للأعلى Events-up
</h2>

<p>
	يُعَد الموجّه <code>bind</code> واضحًا جدًا ويسمح بمشاركة البيانات بين المكوِّن الأب والمكوِّن الابن، ولكن يمكن أن يكون تتبّع جميع القيم المرتبطة ببعضها بعضًا أمرًا صعبًا عندما ينمو تطبيقك بصورة أكبر وأكثر تعقيدًا، لذا يمكنك استخدام نهج مختلف هو نمط الاتصال "props-down, events-up".
</p>

<p>
	يعتمد هذا النمط على المكونات الأبناء التي تتلقى البيانات من آبائها عبر الخاصيات والمكونات الآباء لتحديث حالتها من خلال معالجة الأحداث التي تطلقها المكونات الأبناء، لذا تتدفق الخاصيات للأسفل Flow Down من المكوِّن الأب إلى المكوِّن الابن وتنتشر Bubble Up الأحداث للأعلى من المكوِّن الابن إلى المكوِّن الأب، إذ ينشئ هذا النمط تدفقًا أسهل ثنائي الاتجاه للمعلومات.
</p>

<p>
	لنلقِ نظرةً على كيفية إصدار أحداثنا لإعادة تطبيق وظيفة زر "الحذف Delete" المفقودة، إذ يمكن إنشاء أحداث مخصصة من خلال استخدام الأداة <code>createEventDispatcher</code> التي تعيد الدالة <code>dispatch()‎</code> التي تسمح بإصدار أحداث مخصصة، فإذا أرسلتَ حدثًا، فيجب تمرير اسم الحدث وكائن اختياري به معلومات إضافية تريد تمريرها إلى كل مستمع، كما ستكون هذه البيانات الإضافية متاحةً في الخاصية <code>detail</code> لكائن الحدث.
</p>

<p>
	<strong>ملاحظة</strong>: تشترك الأحداث المخصصة في إطار عمل Svelte بواجهة برمجة التطبيقات نفسها التي تستخدِمها أحداث <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">DOM</a> العادية، كما يمكنك نشر حدث إلى المكوِّن الأب عن طريق تحديد <code>on:event</code> بدونّ أي معالج.
</p>

<p>
	سنعدّل المكون <code>Todo</code> لإصدار الحدث <code>remove</code> عبر تمرير المهمة المحذوفة بوصفها معلومات إضافية.
</p>

<p>
	أضِف أولًا الأسطر التالية إلى الجزء العلوي من القسم <code>&lt;script&gt;</code> للمكوِّن <code>Todo</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_48" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createEventDispatcher </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'svelte'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> createEventDispatcher</span><span class="pun">()</span></pre>

<p>
	عدّل الآن زر "الحذف Delete" في قسم شيفرة HTML بالملف نفسه ليبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_50" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__danger"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> dispatch('remove', todo)}&gt;
  Delete </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">{todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	نصدر الحدث <code>remove</code> من خلال استخدام <code>dispatch('remove', todo)‎</code> ونمرِّر المهام <code>todo</code> المحذوفة بوصفها بيانات إضافية، إذ سيُستدعى المعالج باستخدام كائن الحدث المتوفر مع البيانات الإضافية المتوفرة في الخاصية <code>event.detail</code>.
</p>

<p>
	يجب الآن الاستماع إلى هذا الحدث من داخل الملف Todos.svelte والتصرف وفقًا لذلك، لذا ارجع إلى هذا الملف وعدّل استدعاء المكوِّن <code>&lt;Todo&gt;</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_52" style="">
<span class="tag">&lt;Todo</span><span class="pln"> {</span><span class="atn">todo</span><span class="pln">} </span><span class="atn">on:remove</span><span class="pun">=</span><span class="atv">{e</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> removeTodo(e.detail)} /&gt;</span></pre>

<p>
	يتلقى معالجنا المعامِل <code>e</code> (كائن الحدث) الذي يحتفظ بالمهام المحذوفة في الخاصية <code>detail</code>.
</p>

<p>
	إذا حاولت تجربة تطبيقك مرةً أخرى الآن، فسترى أنّ وظيفة الحذف تعود للعمل، وبذلك نجح حدثنا المخصّص كما توقعنا، كما يرسل مستمع الحدث <code>remove</code> تغيّر البيانات إلى المكوِّن الأب، لذلك سيُحدَّث عنوان الحالة "x out of y items completed" بصورة مناسبة عند حذف المهام.
</p>

<p>
	سنهتم الآن بالحدث <code>update</code> بحيث يمكن إعلام المكوِّن الأب بأيّ مهام مُعدَّلة.
</p>

<h2>
	تحديث المهام
</h2>

<p>
	لا يزال يتعين علينا تنفيذ الوظيفة للسماح بتعديل المهام الحالية، إذ يجب تضمين وضع التعديل في المكوِّن <code>Todo</code>، كما سنعرض حقل الإدخال <code><a href="https://wiki.hsoub.com/HTML/input" rel="external">&lt;input&gt;</a></code> عند الدخول في وضع التعديل للسماح بتعديل اسم المهمة الحالي مع زرين لتأكيد التغييرات أو إلغائها.
</p>

<h3>
	معالجة الأحداث
</h3>

<p>
	أولًا، سنحتاج متغيرًا واحدًا لتتبّع ما إذا كنا في وضع التعديل أم في وضع آخر لتخزين اسم المهمة المُعدَّلة، لذا أضِف تعريفات المتغيرات التالية في الجزء السفلي من القسم <code>&lt;script&gt;</code> للمكوِّن <code>Todo</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_55" style="">
<span class="pln">let editing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">                     </span><span class="com">// تتبّع نمط التعديل</span><span class="pln">
let name </span><span class="pun">=</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">name                    </span><span class="com">// تخزين اسم المهمة المُعدَّلة</span></pre>

<p>
	يجب أن نقرِّر ما هي الأحداث التي سيصدرها المكوِّن <code>Todo</code> كما يلي:
</p>

<ul>
<li>
		يمكننا إصدار أحداث مختلفة لتبديل الحالة وتعديل الاسم مثل <code>updateTodoStatus</code> و <code>updateTodoName</code>.
	</li>
	<li>
		أو يمكننا اتباع نهج أعم وإصدار حدث <code>update</code> واحد لكلتا العمليتين.
	</li>
</ul>
<p>
	سنتخذ النهج الثاني لنتمكن من إظهار طريقة مختلفة، إذ تتمثل ميزة هذا النهج في أنه يمكننا لاحقًا إضافة المزيد من الحقول إلى المهام مع إمكانية معالجة جميع التحديثات باستخدام الحدث نفسه، فلننشئ الدالة <code>update()‎</code> التي ستتلقى التغييرات وتصدر حدث تحديث مع المهام المُعدَّلة، لذا أضف ما يلي مرةً أخرى إلى الجزء السفلي من القسم <code>&lt;script&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_57" style="">
<span class="kwd">function</span><span class="pln"> update</span><span class="pun">(</span><span class="pln">updatedTodo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">todo</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">updatedTodo </span><span class="pun">}</span><span class="pln">    </span><span class="com">// تطبيق تعديلات على المهمة</span><span class="pln">
  dispatch</span><span class="pun">(</span><span class="str">'update'</span><span class="pun">,</span><span class="pln"> todo</span><span class="pun">)</span><span class="pln">              </span><span class="com">// إصدار حدث التحديث</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	استخدمنا صيغة الانتشار Spread Syntax لإعادة المهمة الأصلية مع التعديلات المُطبَّقة عليها.
</p>

<p>
	سننشئ بعد ذلك دوالًا مختلفةً للتعامل مع كل إجراء للمستخدِم، إذ يمكن للمستخدِم حفظ التغييرات أو إلغائها عندما تكون المهمة في وضع التعديل، ويمكن للمستخدِم حذف المهمة أو تعديلها أو تبديل حالتها بين الحالة المكتملة والنشطة عندما لا تكون في وضع التعديل، لذا أضف مجموعة الدوال التالية بعد آخر دالة للتعامل مع هذه الإجراءات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_59" style="">
<span class="kwd">function</span><span class="pln"> onCancel</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name </span><span class="pun">=</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">name                      </span><span class="com">// ‫إعادة المتغير name إلى قيمته الأولية </span><span class="pln">
  editing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">                       </span><span class="com">// والخروج من وضع التعديل</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> onSave</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  update</span><span class="pun">({</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> name </span><span class="pun">})</span><span class="pln">                </span><span class="com">// تحديث اسم المهمة</span><span class="pln">
  editing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">                       </span><span class="com">// والخروج من وضع التعديل</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> onRemove</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  dispatch</span><span class="pun">(</span><span class="str">'remove'</span><span class="pun">,</span><span class="pln"> todo</span><span class="pun">)</span><span class="pln">              </span><span class="com">// إصدار حدث الحذف</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> onEdit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  editing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">                        </span><span class="com">// الدخول في وضع التعديل</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> onToggle</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  update</span><span class="pun">({</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">todo</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">})</span><span class="pln"> </span><span class="com">// تحديث حالة المهمة</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	تحديث ملف شيفرة HTML
</h3>

<p>
	يجب الآن تحديث شيفرة HTML الخاصة بالمكون <code>Todo</code> لاستدعاء الدوال السابقة عند اتخاذ الإجراءات المناسبة، إذ يمكنك التعامل مع وضع التعديل من خلال استخدام المتغير <code>editing</code> الذي له قيمة منطقية، فإذا كانت قيمة هذا المتغير <code>true</code>، فيجب أن يُعرَض حقل الإدخال <code>&lt;input&gt;</code> لتعديل اسم المهمة وزرَّي "الإلغاء Cancel" و"الحفظ Save"؛ أما إذا لم تكن في وضع التعديل، فسيُعرَض مربع الاختيار واسم المهمة وأزرار تعديل المهام وحذفها.
</p>

<p>
	يمكن تحقيق ذلك من خلال استخدام كتلة <code>if</code> التي تصيّر شيفرة HTML شرطيًا، ولكن ضع في الحسبان أنها لن تظهِر أو تخفي شيفرة HTML بناءً على شرط معيّن، وإنما ستضيف وتزيل عناصر نموذج DOM ديناميكيًا اعتمادًا على هذا الشرط.
</p>

<p>
	إذا كانت قيمة المتغير <code>editing</code> هي <code>true</code> مثلًا، فسيعرض إطار عمل Svelte نموذج التحديث؛ أما إذا كانت قيمته <code>false</code>، فسيزيله من نموذج DOM وسيضيف مربع الاختيار، لذا سيكون تعيين قيمة المتغير <code>editing</code> كافيًا لعرض عناصر HTML الصحيحة بفضل خاصية التفاعل في إطار عمل Svelte.
</p>

<p>
	ستكون كتلة <code>if</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_61" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-small"</span><span class="tag">&gt;</span><span class="pln">
{#if editing}
  </span><span class="com">&lt;!-- markup for editing to-do: label, input text, Cancel and Save Button --&gt;</span><span class="pln">
{:else}
  </span><span class="com">&lt;!-- markup for displaying to-do: checkbox, label, Edit and Delete Button --&gt;</span><span class="pln">
{/if}
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	يمثِّل الجزء <code>{‎:else}</code> أو النصف السفلي من كتلة <code>if</code> قسم عدم التعديل، كما سيكون مشابهًا جدًا للقسم الموجود في المكوِّن <code>Todos</code>، ولكن الاختلاف الوحيد بينهما هو أننا نستدعي الدوال <code>onToggle()‎</code> و <code>onEdit()‎</code> و <code>onRemove()‎</code> اعتمادًا على إجراء المستخدِم.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_64" style="">
<span class="pln">{:else}
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"c-cb"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln">
      </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{onToggle}</span><span class="pln"> </span><span class="atn">checked</span><span class="pun">=</span><span class="atv">{todo.completed}</span><span class="pln">
    </span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-label"</span><span class="tag">&gt;</span><span class="pln">{todo.name}</span><span class="tag">&lt;/label&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{onEdit}</span><span class="tag">&gt;</span><span class="pln">
      Edit</span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln"> {todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__danger"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{onRemove}</span><span class="tag">&gt;</span><span class="pln">
      Delete</span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln"> {todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
{/if}
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	تجدر الإشارة إلى ما يلي:
</p>

<ul>
<li>
		ننفّذ الدالة <code>onEdit()‎</code> التي تضبط المتغير <code>editing</code> على القيمة <code>true</code> عندما يضغط المستخدِم على زر "التعديل Edit".
	</li>
	<li>
		نستدعي الدالة <code>onToggle()‎</code> التي تنفذ الدالة <code>update()‎</code> من خلال تمرير كائن مع قيمة <code>completed</code> الجديدة بوصفه معامِلًا عندما ينقر المستخدِم على مربع الاختيار.
	</li>
	<li>
		تصدِر الدالة <code>update()‎</code> الحدث <code>update</code> من خلال تمرير نسخة من المهمة الأصلية مع التغييرات المطبَّقة بوصفها معلومات إضافية.
	</li>
	<li>
		أخيرًا، تصدِر الدالة <code>onRemove()‎</code> الحدث <code>remove</code> من خلال تمرير المهمة <code>todo</code> المراد حذفها بوصفها بيانات إضافية.
	</li>
</ul>
<p>
	ستحتوي واجهة المستخدِم الخاصة بالتعديل -أي النصف العلوي- على حقل الإدخال <code>&lt;input&gt;</code> وزرين لإلغاء التغييرات أو حفظها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_66" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-small"</span><span class="tag">&gt;</span><span class="pln">
{#if editing}
  </span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">on:submit</span><span class="pln">|</span><span class="atn">preventDefault</span><span class="pun">=</span><span class="atv">{onSave}</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-small"</span><span class="pln"> </span><span class="atn">on:keydown</span><span class="pun">=</span><span class="atv">{e</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> e.key === 'Escape' &amp;&amp; onCancel()}&gt;
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-label"</span><span class="tag">&gt;</span><span class="pln">New name for '{todo.name}'</span><span class="tag">&lt;/label&gt;</span><span class="pln">
      </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">bind:value</span><span class="pun">=</span><span class="atv">{name}</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln"> </span><span class="atn">autoComplete</span><span class="pun">=</span><span class="atv">"off"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-text"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn todo-cancel"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{onCancel}</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="tag">&gt;</span><span class="pln">
        Cancel</span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">renaming {todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
        </span><span class="tag">&lt;/button&gt;</span><span class="pln">
      </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary todo-edit"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">disabled</span><span class="pun">=</span><span class="atv">{!name}</span><span class="tag">&gt;</span><span class="pln">
        Save</span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">new name for {todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
      </span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/form&gt;</span><span class="pln">
{:else}
[...]</span></pre>

<p>
	إذا ضغط المستخدِم على زر "التعديل Edit"، فسيُضبَط المتغير <code>editing</code> على القيمة <code>true</code> وسيزيل إطار عمل Svelte شيفرة HTML في الجزء <code>{‎:else}</code> من نموذج DOM وسيستبدله بشيفرة HTML الموجودة في القسم <code>{‎#if‎}</code>.
</p>

<p>
	ستكون الخاصية <code>value</code> الخاصة بالعنصر <code>&lt;input&gt;</code> مرتبطةً بالمتغير <code>name</code>، وستستدعي أزرار إلغاء التغييرات وحفظها الدالتين <code>onCancel()‎</code> و <code>onSave()‎</code> على التوالي كما يلي، وقد أضفنا هاتين الدالتين سابقًا:
</p>

<ul>
<li>
		إذا استُدعيت الدالة <code>onCancel()‎</code>، فستُعاد الخاصية <code>name</code> إلى قيمتها الأصلية عند تمريرها بوصفها خاصيةً Prop وسنخرج من وضع التعديل عن طريق ضبط المتغير <code>editing</code> على القيمة <code>false</code>.
	</li>
	<li>
		إذا استُدعيت الدالة <code>onSave()‎</code>، فسنشغّل الدالة <code>update()‎</code> من خلال تمرير الخاصية <code>name</code> المُعدَّلة، وسنخرج من وضع التعديل.
	</li>
</ul>
<p>
	كما نعطّل زر "الحفظ Save" عندما يكون حقل الإدخال <code>&lt;input&gt;</code> فارغًا باستخدام السمة <code>disabled={!name}‎</code>، كما نسمح للمستخدِم بإلغاء التعديل باستخدام المفتاح <code>Escape</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_68" style="">
<span class="pln">on</span><span class="pun">:</span><span class="pln">keydown</span><span class="pun">={</span><span class="pln">e </span><span class="pun">=&gt;</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">key </span><span class="pun">===</span><span class="pln"> </span><span class="str">'Escape'</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> onCancel</span><span class="pun">()}.</span></pre>

<p>
	كما نستخدِم الخاصية <code>todo.id</code> لإنشاء معرّفات فريدة لعناصر التحكم بحقل الإدخال والتسميات Labels الجديدة.
</p>

<p>
	تبدو شيفرة HTML المعدَّلة الكاملة للمكون <code>Todo</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5670_70" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-small"</span><span class="tag">&gt;</span><span class="pln">
{#if editing}
  </span><span class="com">&lt;!-- markup for editing todo: label, input text, Cancel and Save Button --&gt;</span><span class="pln">
  </span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">on:submit</span><span class="pln">|</span><span class="atn">preventDefault</span><span class="pun">=</span><span class="atv">{onSave}</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-small"</span><span class="pln"> </span><span class="atn">on:keydown</span><span class="pun">=</span><span class="atv">{e</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> e.key === 'Escape' &amp;&amp; onCancel()}&gt;
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-label"</span><span class="tag">&gt;</span><span class="pln">New name for '{todo.name}'</span><span class="tag">&lt;/label&gt;</span><span class="pln">
      </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">bind:value</span><span class="pun">=</span><span class="atv">{name}</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln"> </span><span class="atn">autoComplete</span><span class="pun">=</span><span class="atv">"off"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-text"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn todo-cancel"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{onCancel}</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="tag">&gt;</span><span class="pln">
        Cancel</span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">renaming {todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
        </span><span class="tag">&lt;/button&gt;</span><span class="pln">
      </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary todo-edit"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">disabled</span><span class="pun">=</span><span class="atv">{!name}</span><span class="tag">&gt;</span><span class="pln">
        Save</span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">new name for {todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
      </span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/form&gt;</span><span class="pln">
{:else}
  </span><span class="com">&lt;!-- markup for displaying todo: checkbox, label, Edit and Delete Button --&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"c-cb"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln">
      </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{onToggle}</span><span class="pln"> </span><span class="atn">checked</span><span class="pun">=</span><span class="atv">{todo.completed}</span><span class="pln">
    </span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-label"</span><span class="tag">&gt;</span><span class="pln">{todo.name}</span><span class="tag">&lt;/label&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{onEdit}</span><span class="tag">&gt;</span><span class="pln">
      Edit</span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln"> {todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__danger"</span><span class="pln"> </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{onRemove}</span><span class="tag">&gt;</span><span class="pln">
      Delete</span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln"> {todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
{/if}
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	<strong>ملاحظة</strong>: يمكننا أيضًا تقسيم هذا المكوِّن إلى مكوِّنين مختلفين أحدهما لتعديل المهام والآخر لعرضها، إذ يتلخص الأمر في مدى شعورك بالراحة في التعامل مع هذا المستوى من التعقيد باستخدام مكوِّن واحد، لذا يجب التفكير فيما إذا كان تقسيمه سيمكّنك أكثر من إعادة استخدام هذا المكوِّن في سياق مختلف.
</p>

<p>
	يجب معالجة الحدث <code>update</code> من المكوِّن <code>Todos</code> لتشغيل وظيفة التحديث، لذا أضف معالِج الأحداث التالي في القسم <code>&lt;script&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_72" style="">
<span class="kwd">function</span><span class="pln"> updateTodo</span><span class="pun">(</span><span class="pln">todo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">findIndex</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  todos</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">todos</span><span class="pun">[</span><span class="pln">i</span><span class="pun">],</span><span class="pln"> </span><span class="pun">...</span><span class="pln">todo </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نجد المهمة <code>todo</code> باستخدام معرِّفها <code>id</code> في مصفوفة المهام <code>todos</code> ونحدّث محتواها باستخدام صيغة الانتشار، وقد كان بإمكاننا أيضًا استخدام <code>todos[i‎] = todo</code> في هذه الحالة، ولكن هذا التطبيق أفضل، مما يسمح للمكوِّن <code>Todo</code> بإعادة الأجزاء المُعدَّلة فقط من المهام.
</p>

<p>
	يجب بعد ذلك الاستماع إلى الحدث <code>update</code> في استدعاء المكون <code>&lt;Todo&gt;</code>، وتشغيل الدالة <code>updateTodo()‎</code> عند حدوث ذلك لتغيير المتغير <code>name</code> والحالة <code>completed</code>، لذا عدّل استدعاء المكوِّن <code>&lt;Todo&gt;</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_74" style="">
<span class="pun">{#</span><span class="pln">each filterTodos</span><span class="pun">(</span><span class="pln">filter</span><span class="pun">,</span><span class="pln"> todos</span><span class="pun">)</span><span class="pln"> as todo </span><span class="pun">(</span><span class="pln">todo</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)}</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">li </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"todo"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Todo</span><span class="pln"> </span><span class="pun">{</span><span class="pln">todo</span><span class="pun">}</span><span class="pln">
      on</span><span class="pun">:</span><span class="pln">update</span><span class="pun">={</span><span class="pln">e </span><span class="pun">=&gt;</span><span class="pln"> updateTodo</span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">detail</span><span class="pun">)}</span><span class="pln">
      on</span><span class="pun">:</span><span class="pln">remove</span><span class="pun">={</span><span class="pln">e </span><span class="pun">=&gt;</span><span class="pln"> removeTodo</span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">detail</span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span></pre>

<p>
	جرب تطبيقك مرةً أخرى وسترى أنه يمكنك حذف وإضافة وتعديل وإلغاء تعديل وتبديل حالة اكتمال المهام، وسيُعدَّل عنوان الحالة "x out of y items completed" بطريقة مناسبة عند اكتمال المهام.
</p>

<p>
	يُعَدّ تطبيق نمط "props-down, events-up" في إطار عمل Svelte سهلًا، ولكن يمكن أن يكون الموجّه <code>bind</code> اختيارًا جيدًا للمكونات البسيطة، وسيتيح لك إطار Svelte الاختيار.
</p>

<p>
	<strong>ملاحظة</strong>: يوفِّر إطار Svelte آليات أكثر تقدمًا لمشاركة المعلومات بين المكونات، وهي واجهة Context <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> والمخازن Stores، إذ توفِّر Context <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> آليةً للمكونات وأحفادها للتواصل مع بعضها البعض دون تمرير البيانات والدوال بوصفها خاصيات، أو إرسال الكثير من الأحداث، في حين تتيح المخازن Stores مشاركة البيانات التفاعلية بين المكونات غير المرتبطة بطريقة هرمية.
</p>

<p>
	يمكنك الوصول إلى نسختك من مستودعنا على النحو التالي لمعرفة حالة الشيفرة كما يجب أن تكون في نهاية هذا المقال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_76" style="">
<span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">05</span><span class="pun">-</span><span class="pln">advanced</span><span class="pun">-</span><span class="pln">concepts</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5670_78" style="">
<span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">05</span><span class="pun">-</span><span class="pln">advanced</span><span class="pun">-</span><span class="pln">concepts</span></pre>

<p>
	تذكر تشغيل الأمر <code>npm install &amp;&amp; npm run dev</code> لبدء تشغيل تطبيقك في وضع التطوير، فإذا أردت متابعتنا فابدأ بكتابة الشيفرة <a href="https://svelte.dev/repl/76cc90c43a37452e8c7f70521f88b698?version=3.23.2" rel="external nofollow">باستخدام الأداة REPL</a>.
</p>

<h2>
	الخلاصة
</h2>

<p>
	أضفنا جميع الوظائف المطلوبة لتطبيقنا، إذ يمكننا عرض المهام وإضافتها وتعديلها وحذفها وتمييزها على أنها مكتملة وترشيحها حسب الحالة، كما غطينا في هذا المقال المواضيع التالية:
</p>

<ul>
<li>
		استخراج وظائف مكوِّن جديد.
	</li>
	<li>
		تمرير المعلومات من المكوِّن الابن إلى المكوِّن الأب باستخدام معالج يُستقبَل بوصفه خاصيةً.
	</li>
	<li>
		تمرير المعلومات من المكوِّن الابن إلى المكوِّن الأب باستخدام الموجّه <code>bind</code>.
	</li>
	<li>
		عرض كتل شيفرة HTML المشروطة باستخدام كتلة <code>if</code>.
	</li>
	<li>
		تطبيق نمط الاتصال "props-down, events-up".
	</li>
	<li>
		إنشاء الأحداث المخصصة والاستماع إليها.
	</li>
</ul>
<p>
	سنواصل في المقال التالي من جزئية svelte من هذه السلسلة تقسيم تطبيقنا إلى مكونات ونتعرف على بعض التقنيات المتقدمة للعمل مع نموذج DOM.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_components" rel="external nofollow">Componentizing our Svelte app</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1822/" rel="">التعامل مع المتغيرات والخاصيات في إطار عمل Svelte</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1811/" rel="">إنشاء تطبيق قائمة مهام باستعمال إطار عمل Svelte</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">بدء استخدام إطار العمل Svelte لبناء تطبيقات ويب</a><em> </em>
	</li>
</ul>
]]></description><guid isPermaLink="false">1823</guid><pubDate>Fri, 16 Dec 2022 07:38:20 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x645;&#x62A;&#x63A;&#x64A;&#x631;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x62E;&#x627;&#x635;&#x64A;&#x627;&#x62A; &#x641;&#x64A; &#x625;&#x637;&#x627;&#x631; &#x639;&#x645;&#x644; Svelte</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1822/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_12/6398654c68ede_-----Svelte_----.png.bf2772cc510327f8ebf184b8b7560c41.png" /></p>

<p>
	يمكننا الآن البدء في تطوير الميزات المطلوبة لتطبيق قائمة المهام في إطار عمل Svelte بعد أن أصبح التوصيف والتنسيق جاهزًا، إذ سنستخدِم في هذا المقال المتغيرات والخاصيات Props لجعل تطبيقنا ديناميكيًا، مما يسمح بإضافة وحذف المهام ووضع علامة على المهام المكتملة وترشيحها حسب الحالة.
</p>

<ul>
<li>
		<strong>المتطلبات الأساسية</strong>: يوصَى على الأقل بأن تكون على دراية بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة باستخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471" rel="">سطر الأوامر أو الطرفية</a>، وستحتاج طرفية مثبَّت عليها node وnpm لتصريف وبناء تطبيقك.
	</li>
	<li>
		<strong>الهدف</strong>: تعلّم وتطبيق بعض مفاهيم Svelte الأساسية مثل إنشاء المكونات وتمرير البيانات باستخدام الخاصيات وتصيير Render تعابير <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">جافاسكربت</a> في شيفرة <a href="https://academy.hsoub.com/programming/html/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-html-r1687/" rel="">HTML</a> وتعديل حالة المكونات وتكرارها عبر القوائم.
	</li>
</ul>
<p>
	يمكن متابعة كتابة شيفرتك معنا، لذلك انسخ أولًا مستودع github -إذا لم تفعل ذلك مسبقًا- باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_8" style="">
<span class="pln">git clone https</span><span class="pun">:</span><span class="com">//github.com/opensas/mdn-svelte-tutorial.git</span></pre>

<p>
	ثم يمكنك الوصول إلى حالة التطبيق الحالية من خلال تشغيل الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_11" style="">
<span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">03</span><span class="pun">-</span><span class="pln">adding</span><span class="pun">-</span><span class="pln">dynamic</span><span class="pun">-</span><span class="pln">behavior</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_13" style="">
<span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">03</span><span class="pun">-</span><span class="pln">adding</span><span class="pun">-</span><span class="pln">dynamic</span><span class="pun">-</span><span class="pln">behavior</span></pre>

<p>
	تذكَّر تشغيل الأمر <code>npm install &amp;&amp; npm run dev</code> لبدء تشغيل تطبيقك في وضع التطوير، وإذا أردت متابعتنا فابدأ بكتابة الشيفرة باستخدام الأداة REPL من <a href="https://svelte.dev/repl/c862d964d48d473ca63ab91709a0a5a0?version=3.23.2" rel="external nofollow">هنا</a>.
</p>

<h2>
	التعامل مع المهام
</h2>

<p>
	يعرِض المكوِّن <code>Todos.svelte</code> حاليًا شيفرة HTML ثابتةً لا تتغير، إذًا لنبدأ في جعله أكثر ديناميكيةً، إذ سنأخذ معلومات المهام من شيفرة HTML ونخزنها في المصفوفة <code>todos</code>، كما سننشئ متغيرين لتتبّع العدد الإجمالي للمهام والمهام المكتملة، إذ ستُمثَّل حالة المكوِّن من خلال هذه المتغيرات الثلاثة ذات المستوى الأعلى.
</p>

<p>
	أولًا، أنشئ قسم <code>&lt;script&gt;</code> قبل المكوِّن src/components/Todos.svelte وضَع فيه المحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_15" style="">
<span class="tag">&lt;script&gt;</span><span class="pln">
  let todos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Create a Svelte starter app"</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Create your first component"</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Complete the rest of the tutorial"</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">];</span><span class="pln">

  let totalTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
  let completedTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">todo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">).</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	لنبدأ بعد ذلك بإظهار رسالة الحالة، لذا ابحث عن العنوان <code><a href="https://wiki.hsoub.com/HTML/h1-h6" rel="external">&lt;h2&gt;</a></code> الذي له المعرِّف <code>id</code> بالقيمة <code>list-heading</code> واستبدل العدد الثابت للمهام النشطة والمكتملة بتعابير ديناميكية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_17" style="">
<span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"list-heading"</span><span class="tag">&gt;</span><span class="pln">{completedTodos} out of {totalTodos} items completed</span><span class="tag">&lt;/h2&gt;</span></pre>

<p>
	انتقل إلى التطبيق وسترى الرسالة "‎2 out of 3 items completed" كما كانت سابقًا، ولكن تأتي المعلومات هذه المرة من المصفوفة <code>todos</code>.
</p>

<p>
	أخيرًا، يمكن إثبات ذلك من خلال الانتقال إلى تلك المصفوفة ثم محاولة تغيير بعض قيم الخاصية المكتملة completed لكائن المهمة، ويمكنك إضافة كائن مهمة جديد أيضًا، ولاحظ كيف تُحدَّث الأعداد في الرسالة بطريقة مناسبة.
</p>

<h2>
	إنشاء مهام من بيانات يدخلها المستخدم
</h2>

<p>
	تُعَدّ عناصر المهام المعروضة ثابتةً حاليًا، ونريد تكرار كل عنصر في المصفوفة <code>todos</code> وتصيير Render شيفرة HTML لكل مهمة. ليس لدى لغة HTML طريقة للتعبير عن المنطق مثل التعابير الشرطية والحلقات، ولكن <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">إطار عمل Svelte</a> يمكنه ذلك من خلال استخدام الموجّه <code>{‎#each...‎}</code> للتكرار عبر المصفوفة <code>todos</code>.
</p>

<p>
	يتضمن المعامِل الثاني -إذا كان موجودًا- فهرس العنصر الحالي، كما يمكن توفير تعبير مفتاحي يحدد كل عنصر بطريقة فريدة، وسيستخدِمه إطار Svelte لمعرفة الاختلاف في القائمة عند تغيير البيانات بدلًا من إضافة العناصر أو إزالتها في النهاية، ويُعَدّ تحديد عنصر مفتاحي دائمًا من الممارسات الجيدة، كما يمكن توفير كتلة <code>‎:else</code> التي ستُصيَّر عندما تكون القائمة فارغةً.
</p>

<p>
	أولًا، استبدل <a href="https://wiki.hsoub.com/HTML/ul" rel="external">العنصر &lt;ul&gt;</a> الحالي بالإصدار المبسط التالي لتفهم كيفية العمل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_22" style="">
<span class="tag">&lt;ul&gt;</span><span class="pln">
{#each todos as todo, index (todo.id)}
  </span><span class="tag">&lt;li&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">checked</span><span class="pun">=</span><span class="atv">{todo.completed}</span><span class="tag">/&gt;</span><span class="pln"> {index}. {todo.name} (id: {todo.id})
  </span><span class="tag">&lt;/li&gt;</span><span class="pln">
{:else}
  Nothing to do here!
{/each}
</span><span class="tag">&lt;/ul&gt;</span></pre>

<p>
	ثانيًا، ارجع إلى التطبيق وسترى شيئًا يشبه ما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="113769" href="https://academy.hsoub.com/uploads/monthly_2022_12/01_each-block.png.bc1d8a1a8a435e00da13ee3dfc5b9fc0.png" rel=""><img alt="إنشاء مهام من بيانات يدخلها المستخدم" class="ipsImage ipsImage_thumbnailed" data-fileid="113769" data-unique="yop919uhc" src="https://academy.hsoub.com/uploads/monthly_2022_12/01_each-block.png.bc1d8a1a8a435e00da13ee3dfc5b9fc0.png" style="width: 320px; height: auto;"></a>
</p>

<p>
	رأينا الآن أنّّ كل شيء يعمل جيدًا، فلننشئ عنصر مهمة مكتملة مع كل حلقة للموجّه <code>{‎#each}</code>، ونضمّن فيها المعلومات من المصفوفة <code>todos</code> مثل <code>id</code> و<code>name</code> و<code>completed</code> واستبدل كتلة <code>&lt;ul&gt;</code> الحالية بما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_25" style="">
<span class="com">&lt;!-- Todos --&gt;</span><span class="pln">
</span><span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">role</span><span class="pun">=</span><span class="atv">"list"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-list stack-large"</span><span class="pln"> </span><span class="atn">aria-labelledby</span><span class="pun">=</span><span class="atv">"list-heading"</span><span class="tag">&gt;</span><span class="pln">
  {#each todos as todo (todo.id)}
    </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-small"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"c-cb"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln"> </span><span class="atn">checked</span><span class="pun">=</span><span class="atv">{todo.completed}</span><span class="tag">/&gt;</span><span class="pln">
          </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-label"</span><span class="tag">&gt;</span><span class="pln">
            {todo.name}
          </span><span class="tag">&lt;/label&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn"</span><span class="tag">&gt;</span><span class="pln">
            Edit </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">{todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
          </span><span class="tag">&lt;/button&gt;</span><span class="pln">
          </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__danger"</span><span class="tag">&gt;</span><span class="pln">
            Delete </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">{todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
          </span><span class="tag">&lt;/button&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/li&gt;</span><span class="pln">
  {:else}
    </span><span class="tag">&lt;li&gt;</span><span class="pln">Nothing to do here!</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  {/each}
</span><span class="tag">&lt;/ul&gt;</span></pre>

<p>
	لاحظ كيفية استخدام الأقواس المعقوصة لتضمين تعابير جافاسكربت ضمن سمات HTML كما فعلنا مع السمتين <code>checked</code> و <code>id</code> لمربع الاختيار.
</p>

<p>
	حوّلنا بذلك شيفرة HTML الثابتة إلى قالب ديناميكي جاهز لعرض المهام من حالة المكوِّن.
</p>

<h2>
	التعامل مع الخاصيات
</h2>

<p>
	لا يُعَدّ المكوِّن <code>Todos</code> مفيدًا جدًا بوجود قائمة مهام ثابتة، إذ يمكن تحويل المكون إلى محرّر مهام للأغراض العامة من خلال السماح لأب هذا المكون بالمرور على قائمة المهام لتعديلها، مما يسمح بحفظها في خدمة ويب أو في التخزين المحلي واستعادتها لاحقًا لتحديثها، لذلك لنحوّل المصفوفة إلى خاصية <code>prop</code>.
</p>

<p>
	أولًا، استبدل كتلة <code>let todos = ...‎</code> الموجودة مسبقًا في <code>Todos.svelte</code> بالتعليمة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_27" style="">
<span class="kwd">export</span><span class="pln"> let todos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span></pre>

<p>
	يمكن أن يبدو هذا غريبًا بعض الشيء في البداية، فهذه ليست الطريقة التي تعمل بها تعليمة <code>export</code> في <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-modules-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1286/" rel="">وحدات جافاسكربت</a>، وإنما هي الطريقة التي يوسّع بها إطار عمل Svelte شيفرة جافاسكربت من خلال استخدام صيغة صالحة لهدف جديد.
</p>

<p>
	يستخدِم إطار عمل Svelte في حالتنا الكلمة <code>export</code> لتمييز التصريح عن متغير بوصفه خاصية Property أو Prop، مما يعني أنه يصبح في متناول مستخدِمي المكوِّن، كما يمكنك تحديد قيمة أولية افتراضية للخاصية التي تُستخدَم إذا لم يحدد مستخدِم المكون الخاصية الخاصة بالمكوِّن أو إذا كانت قيمتها الأولية غير محدَّدة عند إنشاء نسخة من المكوِّن، لذا نخبر إطار Svelte من خلال التعليمة <code>export let todos = []‎</code> أنّ المكوِّن <code>Todos.svelte</code> سيقبل السمة <code>todos</code> والتي ستُهيَّأ إلى مصفوفة فارغة عند حذفها.
</p>

<p>
	ثانيًا، ألقِ نظرةً على التطبيق وسترى الرسالة "Nothing to do here!‎" لأننا لا نمرّر حاليًا أيّ قيمة إليه من المكوِّن <code>App.svelte</code>، لذلك سيستخدِم القيمة الافتراضية.
</p>

<p>
	ثالثًا، لننقل مصفوفة مهامنا <code>todos</code> إلى المكوِّن <code>App.svelte</code> ولنمرّرها إلى المكوِّن <code>Todos.svelte</code> بوصفها خاصيةً، لذا عدِّل المكوِّن <code>src/App.svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_30" style="">
<span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Todos</span><span class="pln"> from </span><span class="str">"./components/Todos.svelte"</span><span class="pun">;</span><span class="pln">

  let todos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Create a Svelte starter app"</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Create your first component"</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Complete the rest of the tutorial"</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">];</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="typ">Todos</span><span class="pln"> todos</span><span class="pun">={</span><span class="pln">todos</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span></pre>

<p>
	أخيرًا، يسمح إطار عمل Svelte بتحديد المتغير بوصفه اختصارًا عندما يكون للسمة والمتغير الاسم نفسه، ويمكننا بذلك إعادة كتابة السطر الأخير كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_34" style="">
<span class="tag">&lt;Todos</span><span class="pln"> {</span><span class="atn">todos</span><span class="pln">} </span><span class="tag">/&gt;</span></pre>

<p>
	يجب أن تُصيَّر المهام كما كانت سابقًا باستثناء أننا نمرّرها الآن من المكوِّن <code>App.svelte</code>.
</p>

<h2>
	تبديل وإزالة المهام
</h2>

<p>
	سنضيف الآن بعض الوظائف لتبديل حالة المهمة، إذ يحتوي إطار Svelte على الموجّه <code>on:eventname</code> للاستماع إلى أحداث <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">DOM</a>، لذا أضِف معالجًا إلى الحدث <code>on:click</code> الخاص بمربع الاختيار لتبديل القيمة المكتملة.
</p>

<p>
	أولًا، عدّل العنصر <code>&lt;input type="checkbox"‎&gt;</code> في المكوِّن <code>src/components/Todos.svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_37" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-{todo.id}"</span><span class="pln">
  </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> todo.completed = !todo.completed}
  checked={todo.completed}
/&gt;</span></pre>

<p>
	ثانيًا، سنضيف دالة لإزالة مهمة من المصفوفة <code>todos</code>، لذا أضف الدالة <code>removeTodo()‎</code> في الجزء السفلي من القسم <code>&lt;script&gt;</code> في المكوِّن <code>Todos.svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_39" style="">
<span class="kwd">function</span><span class="pln"> removeTodo</span><span class="pun">(</span><span class="pln">todo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنستدعي بعد ذلك هذه الدالة باستخدام زر "الحذف Delete"، لذا عدّلها باستخدام الحدث <code>click</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_41" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__danger"</span><span class="pln">
  </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> removeTodo(todo)}
&gt;
  Delete </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">{todo.name}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	يُعَدّ تمرير نتيجة تنفيذ دالة بوصفها معالجًا بدلًا من تمرير الدالة من الأخطاء الشائعة جدًا في المعالجات في إطار Svelte، فإذا حدّدت <code>on:click={removeTodo(todo)}‎</code> مثلًا، فستُنفَّذ الدالة <code>removeTodo(todo)‎</code> وستُمرَّر النتيجة بوصفها معالِجًا، لذا يجب تحديد <code>on:click={() =&gt; removeTodo(todo)}‎</code> على أساس معالج، فإذا لم تأخذ الدالة <code>removeTodo()‎</code> أيّ معامِل، فيمكنك استخدام <code>on:event={removeTodo}‎</code>، ولكن لا يمكنك استخدام <code>on:event={removeTodo()}‎</code>، كما أنّ ليس هذا الشكل صيغةً خاصةً من Svelte، وإنما استخدمنا دوال <a href="https://academy.hsoub.com/programming/javascript/%D9%86%D8%B8%D8%B1%D8%A9-%D8%AA%D9%81%D8%B5%D9%8A%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B3%D9%87%D9%85%D9%8A%D8%A9-arrow-functions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r880/" rel="">جافاسكربت السهمية Arrow Functions</a> العادية.
</p>

<p>
	يمكننا الآن حذف المهام، إذ تُزال المهام ذات الصلة من المصفوفة <code>todos</code> عند الضغط على زر حذف عنصر المهمة، وتُحدَّث واجهة المستخدِم لعدم إظهاره لاحقًا، كما يمكننا الآن تحديد مربعات الاختيار، وستُحدَّث الحالة المكتملة للمهام ذات الصلة في المصفوفة <code>todos</code>، لكن لا يُحدَّث العنوان "x out of y items completed".
</p>

<h2>
	المهام التفاعلية
</h2>

<p>
	يعرِف إطار Svelte كيفية تحديث واجهة المستخدِم في كل مرة تُعدَّل فيها قيمة متغير المستوى الأعلى للمكوِّن، حيث تُعدَّل في تطبيقنا قيمة المصفوفة <code>todos</code> مباشرةً في كل مرة تُبدَّل أو تُحذَف فيها المهام المطلوبة، وبالتالي سيحدّث إطار Svelte نموذج DOM تلقائيًا.
</p>

<p>
	لا ينطبق الأمر نفسه على المتغيرين <code>totalTodos</code> و<code>completedTodos</code>، إذ يُسنَد إليهما قيمة عند إنشاء نسخة من المكوِّن وينفَّذ السكربت في الشيفرة التالية، ولكن لا تُعدَّل قيمتهما بعد ذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_43" style="">
<span class="pln">let totalTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">length
let completedTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">todo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">).</span><span class="pln">length</span></pre>

<p>
	يمكننا إعادة حسابهما بعد تبديل المهام وإزالتها، ولكن هناك طريقة أسهل لذلك، حيث نخبر إطار Svelte بأننا نريد أن يكون المتغيران <code>totalTodos</code> و <code>completedTodos</code> تفاعليين من خلال جعلهما مسبوقين بالرمز <code>:$‎</code>، إذ سينشئ إطار Svelte الشيفرة لتحديثهما تلقائيًا كلما تغيرت البيانات التي يعتمدان عليها.
</p>

<p>
	<strong>ملاحظة</strong>: يستخدِم إطار Svelte صيغة تعليمة تسمية جافاسكربت <code>:$‎</code> لتمييز التعليمات التفاعلية مثل الكلمة <code>export</code> المستخدَمة للتصريح عن الخاصيات، إذ يُعَد هذا المثال مثالًا آخرًا يستفيد فيه إطار Svelte من صيغة جافاسكربت صالحة مع إعطائها هدفًا جديدًا، وهو في هذه الحالة "إعادة تشغيل هذه الشيفرة كلما تغيرت أيّ من القيم المشار إليها".
</p>

<p>
	عدِّل تعريف المتغيرين <code>totalTodos</code> و<code>completedTodos</code> ضمن الملف <code>src/components/Todos.svelte</code> لتبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_45" style="">
<span class="pln">$</span><span class="pun">:</span><span class="pln"> totalTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">length
$</span><span class="pun">:</span><span class="pln"> completedTodos </span><span class="pun">=</span><span class="pln"> todos</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">((</span><span class="pln">todo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> todo</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">).</span><span class="pln">length</span></pre>

<p>
	إذا فحصت تطبيقك الآن، فسترى تحديث أرقام العناوين عند اكتمال المهام أو حذفها.
</p>

<p>
	يحلّل مصرِّف Svelte الشيفرة لإنشاء شجرة اعتماديات، ثم ينشئ شيفرة جافاسكربت لإعادة تقييم كل تعليمة تفاعلية كلما حُدِّثت إحدى اعتمادياتها، كما تُطبَّق التفاعلية في Svelte بطريقة خفيفة الوزن وفعالة دون استخدام المستمعِين Listeners أو التوابع الجالبة Getters أو الضابطة Setters أو أيّ آلية معقدة أخرى.
</p>

<h2>
	إضافة مهام جديدة
</h2>

<p>
	يجب الآن إضافة بعض الوظائف لإضافة مهام جديدة.
</p>

<p>
	أولًا، سننشئ متغيرًا للاحتفاظ بنص المهام الجديدة، لذا أضف التصريح التالي إلى القسم <code>&lt;script&gt;</code> في الملف Todos.svelte:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_49" style="">
<span class="pln">let newTodoName </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span></pre>

<p>
	سنستخدِم الآن هذه القيمة في <a href="https://wiki.hsoub.com/HTML/input" rel="external">العنصر &lt;input&gt;</a> لإضافة مهام جديدة، وسنحتاج ربط المتغير <code>newTodoName</code> بدخل <code>todo-0</code>، بحيث تبقى قيمة المتغير <code>newTodoName</code> متزامنةً مع الخاصية <code>value</code> الخاصة بالعنصر <code>&lt;input&gt;</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_51" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">{newTodoName}</span><span class="pln"> </span><span class="atn">on:keydown</span><span class="pun">=</span><span class="atv">{(e)</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> newTodoName = e.target.value} /&gt;</span></pre>

<p>
	كلما تغيرت قيمة المتغير <code>newTodoName</code>، فسينتقل هذا التغيير إلى السمة <code>value</code> الخاصة بحقل الإدخال، وكلما ضُغِط على مفتاح في حقل الإدخال، فسنحدّث محتويات المتغير <code>newTodoName</code>، إذ يُعَدّ ذلك تطبيقًا يدويًا لربط البيانات ثنائي الاتجاه لحقل الإدخال، لكننا لسنا بحاجة لهذه الآلية، إذ يوفِّر إطار Svelte طريقةً أسهل لربط أيّ خاصية بمتغير باستخدام الموجّه <code>bind:property</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_55" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">bind:value</span><span class="pun">=</span><span class="atv">{newTodoName}</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	إذًا لنعدّل حقل الإدخال <code>todo-0</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_57" style="">
<span class="tag">&lt;input</span><span class="pln">
  </span><span class="atn">bind:value</span><span class="pun">=</span><span class="atv">{newTodoName}</span><span class="pln">
  </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln">
  </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-0"</span><span class="pln">
  </span><span class="atn">autocomplete</span><span class="pun">=</span><span class="atv">"off"</span><span class="pln">
  </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"input input__lg"</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	يمكن اختبار نجاح هذه الطريقة من خلال إضافة تعليمة تفاعلية لتسجيل محتويات المتغير <code>newTodoName</code>، لذا أضف مقتطف الشيفرة التالي في نهاية القسم <code>&lt;script&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_59" style="">
<span class="pln">$</span><span class="pun">:</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'newTodoName: '</span><span class="pun">,</span><span class="pln"> newTodoName</span><span class="pun">)</span></pre>

<p>
	<strong>ملاحظة</strong>: لا تقتصر التعليمات التفاعلية على التصريح عن المتغيرات، إذ يمكنك وضع أيّ تعليمة جافاسكربت بعد الرمز <code>:$‎</code>.
</p>

<p>
	ارجع الآن إلى المضيف المحلي <code>localhost:5042</code> واضغط على الاختصار <code>Ctrl + Shift + K</code> لفتح طرفية المتصفح واكتب شيئًا ما في حقل الإدخال، ويجب أن ترى إدخالاتك مسجلةً، كما يمكنك الآن حذف التابع <code>console.log()‎</code> التفاعلي إذا رغبت في ذلك.
</p>

<p>
	سننشئ بعد ذلك دالةً لإضافة مهمة جديدة وهي الدالة <code>addTodo()‎</code> التي ستدفع كائن <code>todo</code> جديد إلى المصفوفة <code>todos</code>، لذا أضف ما يلي إلى الجزء السفلي من كتلة <code>&lt;script&gt;</code> ضمن الملف <code>src/components/Todos.svelte</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_61" style="">
<span class="kwd">function</span><span class="pln"> addTodo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos</span><span class="pun">.</span><span class="pln">push</span><span class="pun">({</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">999</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> newTodoName</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
  newTodoName </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<strong>ملاحظة</strong>: سنسنِد حاليًا المعرِّف <code>id</code> نفسه لكل مهمة، ولكن لا تقلق إذ سنصلح ذلك لاحقًا.
</p>

<p>
	نريد الآن تحديث ملف HTML لاستدعاء الدالة <code>addTodo()‎</code> كلما أُرسِل النموذج، لذا عدّل وسم فتح النموذج <code>NewTodo</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_63" style="">
<span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">on:submit</span><span class="pln">|</span><span class="atn">preventDefault</span><span class="pun">=</span><span class="atv">{addTodo}</span><span class="tag">&gt;</span></pre>

<p>
	يدعم الموجّه <code>on:eventname</code> إضافة مُعدِّلات إلى حدث DOM باستخدام المحرف <code>|</code>، حيث يخبر المُعدِّل <code>preventDefault</code> إطار Svelte بإنشاء شيفرة لاستدعاء التابع <code>event.preventDefault()‎</code> قبل تشغيل المعالج.
</p>

<p>
	إذا حاولت إضافة مهام جديدة، فستُضاف هذه المهام الجديدة إلى المصفوفة <code>todos</code>، ولكن لن تُحدَّث واجهة المستخدِم، وتذكَّر أنه في إطار Svelte يبدأ التفاعل باستخدام الإسنادات، وهذا يعني تنفيذ الدالة <code>addTodo()‎</code> وإضافة عنصر إلى المصفوفة <code>todos</code>، ولكن لن يكتشف إطار Svelte أن تابع الدفع قد عدّل المصفوفة، وبذلك لن يحدّث مهام العنصر <code>&lt;ul&gt;</code>، كما ستؤدي إضافة <code>todos = todos</code> إلى نهاية الدالة <code>addTodo()‎</code> إلى حل هذه المشكلة، ولكن يبدو تضمين ذلك في نهاية الدالة أمرًا غريبًا، لذلك سنأخذ التابع <code>push()‎</code> مع استخدام صيغة الانتشار Spread Syntax لتحقيق النتيجة نفسها، إذ سنسند قيمة إلى المصفوفة <code>todos</code> تساوي المصفوفة <code>todos</code> بالإضافة إلى الكائن الجديد.
</p>

<p>
	<strong>ملاحظة</strong>: المصفوفة <code>Array</code> لديها العديد من العمليات المتغيرة مثل <code>push()‎</code> و <code>pop()‎</code> و <code>splice()‎</code> و <code>shift()‎</code> و <code>unshift()‎</code> و <code>reverse()‎</code> و <code>sort()‎</code> التي يمكن أن يتسبب استخدامها في حدوث آثار جانبية وأخطاء يصعب تتبعها، لذا نتجنب تغيّر المصفوفة باستخدام صيغة الانتشار بدلًا من التابع <code>push()‎</code>، ويُعَدّ ذلك من الممارسات جيدة.
</p>

<p>
	عدّل الدالة <code>addTodo()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_65" style="">
<span class="kwd">function</span><span class="pln"> addTodo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[...</span><span class="pln">todos</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">999</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> newTodoName</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}]</span><span class="pln">
  newTodoName </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	إعطاء كل مهمة معرفا فريدا
</h2>

<p>
	إذا حاولت إضافة مهام جديدة في تطبيقك الآن، فستتمكن من إضافة مهام جديدة وستظهر في <a href="https://academy.hsoub.com/design/user-interface/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-ui-r652/" rel="">واجهة المستخدِم</a> أيضًا، ولكن إذا جربته مرةً ثانية، فلن يعمل، وستتلقى رسالة تقول "Error: Cannot have duplicate keys in a keyed each"، أي نحتاج إلى معرِّفات فريدة لمهامنا.
</p>

<p>
	لنصرّح أولًا عن المتغير <code>newTodoId</code> يُحسَب من عدد المهام زائد 1، ولنجعله تفاعليًا، لذا أضِف مقتطف الشيفرة التالي إلى القسم <code>&lt;script&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_67" style="">
<span class="pln">let newTodoId
  $</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">totalTodos </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      newTodoId </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      newTodoId </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(...</span><span class="pln">todos</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">t</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span></pre>

<p>
	<strong>ملاحظة</strong>: لا تقتصر التعليمات التفاعلية على سطر واحد One-liners، كما يمكن استخدام التعليمة التفاعلية الآتية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1002_6" style="">
<span class="pln"> </span><span class="pun">‎</span><span class="pln">$</span><span class="pun">:</span><span class="pln"> newTodoId </span><span class="pun">=</span><span class="pln"> totalTodos </span><span class="pun">?</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(...</span><span class="pln">todos</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	والتي تُعَدّ مفيدةً أيضًا، ولكنه أقل قابليةً للقراءة.
</p>

<p>
	يحلّل المصرِّف التعليمة التفاعلية بأكملها، ويكتشف أنها تعتمد على المتغير <code>totalTodos</code> والمصفوفة <code>todos</code>. لذا كلما عُدِّل أيّ منهما، فسيُعاد تقييم هذه الشيفرة وتحديث <code>newTodoId</code> وفقًا لذلك، ولنستخدِم ذلك في الدالة <code>addTodo()‎</code>، ولنعدّلها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_71" style="">
<span class="kwd">function</span><span class="pln"> addTodo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  todos </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[...</span><span class="pln">todos</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> newTodoId</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> newTodoName</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}]</span><span class="pln">
  newTodoName </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	ترشيح المهام حسب الحالة
</h2>

<p>
	لنطبّق الآن القدرة على ترشيح مهامنا حسب الحالة، لذا سننشئ متغيرًا للاحتفاظ بالمرشِّح الحالي، ودالة مساعدة ستعيد المهام المُرشَّحة.
</p>

<p>
	أولًا، أضف ما يلي في الجزء السفلي من القسم <code>&lt;script&gt;</code>:
</p>

<pre class="ipsCode">
let filter = 'all'
  const filterTodos = (filter, todos) =&gt;
    filter === 'active' ? todos.filter((t) =&gt; !t.completed) :
    filter === 'completed' ? todos.filter((t) =&gt; t.completed) :
    todos
</pre>

<p>
	نستخدِم المتغير <code>filter</code> للتحكم في مرشّح جميع المهام <code>all</code> أو المهام النشطة <code>active</code> أو المكتملة <code>completed</code>، إذ سيؤدي إسناد إحدى هذه القيم إلى المتغير <code>filter</code> إلى تفعيل المرشح وتحديث قائمة المهام، إذ ستتلقى الدالة <code>filterTodos()‎</code> المرشِّح الحالي وقائمة المهام وستعيد مصفوفةً جديدةً من المهام المُرشَّحة وفقًا لذلك.
</p>

<p>
	لنحدّث بعد ذلك شيفرة HTML الخاصة بزر الترشيح لجعله ديناميكيًا ولنحدّث المرشِّح الحالي عندما يضغط المستخدِّم على أحد أزرار الترشيح كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_73" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"filters btn-group stack-exception"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn toggle-btn"</span><span class="pln"> </span><span class="atn">class:btn__primary</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'all'</span><span class="pln">} </span><span class="atn">aria-pressed</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'all'</span><span class="pln">} </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()=</span><span class="tag">&gt;</span><span class="pln"> filter = 'all'} &gt;
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Show</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span&gt;</span><span class="pln">All</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">tasks</span><span class="tag">&lt;/span&gt;</span><span class="pln">
  </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn toggle-btn"</span><span class="pln"> </span><span class="atn">class:btn__primary</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'active'</span><span class="pln">} </span><span class="atn">aria-pressed</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'active'</span><span class="pln">} </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()=</span><span class="tag">&gt;</span><span class="pln"> filter = 'active'} &gt;
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Show</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span&gt;</span><span class="pln">Active</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">tasks</span><span class="tag">&lt;/span&gt;</span><span class="pln">
  </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn toggle-btn"</span><span class="pln"> </span><span class="atn">class:btn__primary</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'completed'</span><span class="pln">} </span><span class="atn">aria-pressed</span><span class="pun">=</span><span class="atv">{filter</span><span class="pln"> </span><span class="atv">==</span><span class="pun">=</span><span class="pln"> </span><span class="atv">'completed'</span><span class="pln">} </span><span class="atn">on:click</span><span class="pun">=</span><span class="atv">{()=</span><span class="tag">&gt;</span><span class="pln"> filter = 'completed'} &gt;
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Show</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span&gt;</span><span class="pln">Completed</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">tasks</span><span class="tag">&lt;/span&gt;</span><span class="pln">
  </span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	سنعرِض المرشِّح الحالي من خلال تطبيق الصنف <code>btn__primary</code> على زر ترشيح المهام النشطة، ويمكنك تطبيق أصناف تنسيق <a href="https://academy.hsoub.com/programming/css/%d8%aa%d8%b9%d8%b1%d9%91%d9%81-%d8%b9%d9%84%d9%89-%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d8%a7%d8%aa-css-r70/" rel="">CSS</a> شرطيًا على عنصر من خلال استخدام الموجِّه <code>class:name={value}‎</code>، فإذا قُيِّمت عبارة القيمة على أنها صحيحة، فسيُطبَّق اسم الصنف، كما يمكنك إضافة العديد من هذه الموجّهات بشروط مختلفة إلى العنصر نفسه، لذلك إذا كانت التعليمة <code>class:btn__primary={filter === 'all'}‎</code>، فسيطبّق إطار Svelte الصنف <code>btn__primary</code> إذا كان المرشح يساوي جميع المهام <code>all</code>.
</p>

<p>
	<strong>ملاحظة</strong>: يوفِّر إطار العمل Svelte اختصارًا يتيح لنا إمكانية اختصار <code>&lt;div class:active={active}‎&gt;</code> إلى <code>&lt;div class:active&gt;</code> عندما يتطابق الصنف Class مع اسم المتغير.
</p>

<p>
	يحدث شيء مشابه مع <code>aria-pressed={filter === 'all'}‎</code> عند تقييم تعبير جافاسكربت الممرَّر بين الأقواس المعقوصة إلى قيمة صحيحة، حيث ستُضاف السمة <code>aria-pressed</code> إلى الزر، وبالتالي سنحدِّث متغير <code>filter</code> باستخدام <code>class:btn__primary={filter === 'all'}‎</code> كلما نقرنا على الزر.
</p>

<p>
	يجب الآن استخدام الدالة المساعدة في حلقة <code>{‎#each}</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7166_76" style="">
<span class="pln">...
  </span><span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">role</span><span class="pun">=</span><span class="atv">"list"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-list stack-large"</span><span class="pln"> </span><span class="atn">aria-labelledby</span><span class="pun">=</span><span class="atv">"list-heading"</span><span class="tag">&gt;</span><span class="pln">
  {#each filterTodos(filter, todos) as todo (todo.id)}
...</span></pre>

<p>
	يكتشف إطار Svelte بعد تحليل شيفرتنا أنّ الدالة <code>filterTodos()‎</code> تعتمد على المتغيرين <code>filter</code> و <code>todos</code>، وكلما تغيرت أيّ من هذه الاعتماديات، فسيُحدَّث نموذج DOM وفقًا لذلك، لذا كلما تغيَّر المتغيران <code>filter</code> و<code>todos</code>، فسيُعاد تقييم الدالة <code>filterTodos()‎</code> وستُحدَّث العناصر الموجودة ضمن الحلقة.
</p>

<p>
	<strong>ملاحظة</strong>: يمكن أن تكون التفاعلية خادعةً في بعض الأحيان، إذ يتعرّف إطار Svelte على المتغير <code>filter</code> بوصفه اعتماديةً لأننا نشير إليه في التعبير<code>filterTodos(filter, todo)‎</code>، إذ يُعَدّ المتغير <code>filter</code> متغيرًا من المستوى الأعلى، لذلك يمكن إزالته من معامِلات الدالة المساعدة واستدعائه بالشكل: <code>filterTodos(todo)‎</code>، كما يمكن أن ينجح هذا الأمر، ولكن ليس لدى إطار Svelte الآن طريقةً لمعرفة أنّ <code>‎{‎#each filterTodos(todos)... }‎</code> يعتمد على المتغير <code>filter</code>، ولن تُحدَّث قائمة المهام المُرشَّحة عندما يتغير المرشّح، وتذكَّر دائمًا أنّ إطار Svelte يحلِّل الشيفرة لاكتشاف الاعتماديات، لذلك يُفضَّل أن تكون صريحًا بشأنه وألّا تعتمد على رؤية متغيرات المستوى الأعلى، كما يُعَدّ جعل الشيفرة واضحةً وصريحةً بشأن المعلومات التي تستخدِمها من الممارسات الجيدة.
</p>

<p>
	يمكنك الوصول إلى نسختك من مستودعنا على النحو التالي لمعرفة حالة الشيفرة كما يجب أن تكون في نهاية هذا المقال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_78" style="">
<span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">04</span><span class="pun">-</span><span class="pln">componentizing</span><span class="pun">-</span><span class="pln">our</span><span class="pun">-</span><span class="pln">app</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7166_80" style="">
<span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">04</span><span class="pun">-</span><span class="pln">componentizing</span><span class="pun">-</span><span class="pln">our</span><span class="pun">-</span><span class="pln">app</span></pre>

<p>
	تذكَّر تشغيل الأمر <code>npm install &amp;&amp; npm run dev</code> لبدء تشغيل تطبيقك في وضع التطوير، فإذا أردت متابعتنا، فابدأ بكتابة الشيفرة باستخدام <a href="https://svelte.dev/repl/99b9eb228b404a2f8c8959b22c0a40d3?version=3.23.2" rel="external nofollow">الأداة REPL</a>.
</p>

<h2>
	الخلاصة
</h2>

<p>
	طبّقنا في هذا المقال معظم الوظائف المطلوبة، إذ يمكن لتطبيقنا عرض وإضافة وحذف المهام وتبديل حالتها المكتملة وإظهار عدد المهام المكتملة وتطبيق المرشحات، حيث غطينا المواضيع التالية:
</p>

<ul>
<li>
		إنشاء واستخدام المكونات.
	</li>
	<li>
		تحويل شيفرة HTML الثابتة إلى قالب حي.
	</li>
	<li>
		تضمين تعابير جافاسكربت في شيفرة HTML.
	</li>
	<li>
		التكرار على القوائم باستخدام الموجّه <code>{‎#each}</code>.
	</li>
	<li>
		تمرير المعلومات بين المكونات باستخدام الخاصيات.
	</li>
	<li>
		الاستماع إلى أحداث DOM.
	</li>
	<li>
		التصريح عن التعليمات التفاعلية.
	</li>
	<li>
		تنقيح الأخطاء الأساسي باستخدام التابع <code>console.log()‎</code> والتعليمات التفاعلية.
	</li>
	<li>
		ربط خاصيات HTML بالموجّه <code>bind:property</code>.
	</li>
	<li>
		بدء التفاعل باستخدام الإسنادات.
	</li>
	<li>
		استخدام العبارات التفاعلية لترشيح البيانات.
	</li>
	<li>
		التعريف الصريح عن الاعتماديات التفاعلية.
	</li>
</ul>
<p>
	سنضيف مزيدًا من الوظائف التي ستسمح للمستخدِمين بتعديل المهام في المقال التالي.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_variables_props" rel="external nofollow">Dynamic behavior in Svelte: working with variables and props</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">بدء استخدام إطار العمل Svelte لبناء تطبيقات ويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1811/" rel="">إنشاء تطبيق قائمة مهام باستعمال إطار عمل Svelte</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1822</guid><pubDate>Wed, 14 Dec 2022 16:08:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x642;&#x627;&#x626;&#x645;&#x629; &#x645;&#x647;&#x627;&#x645; &#x628;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x625;&#x637;&#x627;&#x631; &#x639;&#x645;&#x644; Svelte</title><link>https://academy.hsoub.com/programming/javascript/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-svelte-r1811/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_12/63905f29cd7c6_-------Svelte.png.224062693adc482b7f508869ab72d3e2.png" /></p>
<p>
	يمكننا الآن البدء في إنشاء تطبيقنا مثل تطبيق قائمة المهام بعد أن فهمنا الأمور الأساسية في <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-framework/" rel="">إطار عمل</a> Svelte في <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">المقال السابق</a>، إذ سنلقي في هذا المقال نظرةً على الوظائف المطلوبة لتطبيقنا أولًا ثم سننشئ المكوِّن <code>Todos.svelte</code> وسنضع شيفرة HTML وشيفرة التنسيق الثابتة في مكانها، وبالتالي سيصبح كل شيء جاهزًا لبدء تطوير ميزات تطبيق قائمة المهام التي سننتقل إليها في المقالات اللاحقة.
</p>

<p>
	نريد أن يتمكن المستخدِمون من تصفح المهام وإضافتها وحذفها ووضع علامة عليها بوصفها مكتملةً، كما سنلقي نظرةً على بعض المفاهيم الأكثر تقدمًا.
</p>

<ul>
	<li>
		<strong>المتطلبات الأساسية</strong>: يوصَى على الأقل بأن تكون على دراية بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة باستخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471/" rel="">سطر الأوامر أو الطرفية</a>، وستحتاج طرفية مثبَّت عليها node وnpm لتصريف وبناء تطبيقك.
	</li>
	<li>
		<strong>الهدف</strong>: معرفة كيفية إنشاء مكوِّن Svelte وتصييره في مكوِّن آخر وتمرير البيانات إليه باستخدام الخاصيات Props وحفظ حالته.
	</li>
</ul>

<p>
	يمكن متابعة كتابة شيفرتك معنا، لذلك انسخ أولًا مستودع github -إذا لم تفعل ذلك مسبقًا- باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5708_7" style=""><span class="pln">git clone https</span><span class="pun">:</span><span class="com">//github.com/opensas/mdn-svelte-tutorial.git</span></pre>

<p>
	ثم يمكنك الوصول إلى حالة التطبيق الحالية من تشغيل الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5708_9" style=""><span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">02</span><span class="pun">-</span><span class="pln">starting</span><span class="pun">-</span><span class="pln">our</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">app</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5708_11" style=""><span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">02</span><span class="pun">-</span><span class="pln">starting</span><span class="pun">-</span><span class="pln">our</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">app</span></pre>

<p>
	تذكَّر تشغيل الأمر التالي لبدء تشغيل تطبيقك في وضع التطوير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5708_13" style=""><span class="pln">npm install </span><span class="pun">&amp;&amp;</span><span class="pln"> npm run dev</span></pre>

<p>
	فإذا أردت متابعتنا فابدأ بكتابة الشيفرة باستخدام <a href="https://svelte.dev/repl/b7b831ea3a354d3789cefbc31e2ca495?version=3.23.2" rel="external nofollow">أداة REPL</a>.
</p>

<h2>
	ميزات تطبيق قائمة المهام
</h2>

<p>
	سيبدو تطبيق قائمة المهام كما يلي بمجرد أن يصبح جاهزًا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="113460" href="https://academy.hsoub.com/uploads/monthly_2022_12/01_todo-list-app.png.f4a995705e1624722c32ee65b320a3c5.png" rel="" data-fileext="png"><img alt="تطبيق قائمة المهام" class="ipsImage ipsImage_thumbnailed" data-fileid="113460" data-unique="3rka8brme" style="width: 400px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/01_todo-list-app.thumb.png.1d34ea9be39bee7c5ca6cf5d4c30e94b.png"></a>
</p>

<p>
	سيتمكّن المستخدِم من تطبيق الأمور التالية باستخدام <a href="https://academy.hsoub.com/design/user-interface/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-ui-r652/" rel="">واجهة المستخدِم</a>:
</p>

<ul>
	<li>
		تصفح المهام.
	</li>
	<li>
		وضع علامة على المهام المكتملة أو تعليقها دون حذفها.
	</li>
	<li>
		إزالة المهام.
	</li>
	<li>
		إضافة مهام جديدة.
	</li>
	<li>
		ترشيح المهام حسب الحالة: جميع المهام أو المهام النشطة أو المهام المكتملة.
	</li>
	<li>
		تعديل المهام.
	</li>
	<li>
		وضع علامة على جميع المهام بوصفها نشطةً أو مكتملةً.
	</li>
	<li>
		إزالة جميع المهام المكتملة.
	</li>
</ul>

<h2>
	إنشاء المكون الأول
</h2>

<p>
	لننشئ المكوِّن <code>Todos.svelte</code> الذي سيحتوي على قائمة المهام.
</p>

<p>
	أولًا، أنشئ مجلدًا جديدًا بالاسم src/components.
</p>

<p>
	<strong>ملاحظة</strong>: يمكنك وضع مكوناتك في أيّ مكان ضمن المجلد src، ولكن المجلد components هو اصطلاح معروف يجب اتباعه، مما يسمح لك بالعثور على مكوناتك بسهولة.
</p>

<p>
	ثانيًا، أنشئ ملفًا بالاسم src/components/Todos.svelte بحيث يحوي ما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5708_19" style=""><span class="tag">&lt;h1&gt;</span><span class="pln">Svelte To-Do list</span><span class="tag">&lt;/h1&gt;</span></pre>

<p>
	ثالثًا، عدّل العنصر <code>title</code> في الملف public/index.html ليحتوي على النص "Svelte To-do list" كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5708_22" style=""><span class="tag">&lt;title&gt;</span><span class="pln">Svelte To-Do list</span><span class="tag">&lt;/title&gt;</span></pre>

<p>
	رابعًا، افتح الملف src/App.svelte واستبدل محتوياته بما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5708_24" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Todos</span><span class="pln"> from </span><span class="str">'./components/Todos.svelte'</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;Todos</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	سيصدر إطار عمل Svelte في وضع التطوير تحذيرًا في طرفية المتصفح عند تحديد خاصية غير موجودة في المكوِّن مثل تحديد الخاصية <code>name</code> عند إنشاء نسخة من المكون <code>App</code> ضمن الملف src/main.js، إذ لا تُستخدَم هذه الخاصية ضمن المكوِّن <code>App</code>، كما يجب أن تعطيك الطرفية حاليًا رسالة مثل الرسالة "‎<app> was created with unknown prop 'name'‎"، لكن يمكنك حل هذه المشكلة من خلال إزالة الخاصية <code>name</code> من src/main.js ويجب أن يبدو الآن كما يلي:</app>
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5708_26" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> from </span><span class="str">'./App.svelte'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">App</span><span class="pun">({</span><span class="pln">
  target</span><span class="pun">:</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> app</span></pre>

<p>
	إذا تحققت من <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عنوان URL</a> لخادم الاختبار، فسترى تصيير المكوِّن <code>Todos.svelte</code> كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="113461" href="https://academy.hsoub.com/uploads/monthly_2022_12/02_todos-component-rendered.png.ca73a89a7b368c65026423357619b351.png" rel="" data-fileext="png"><img alt="تصيير المكوِّن Todos.svelte" class="ipsImage ipsImage_thumbnailed" data-fileid="113461" data-unique="a1q7es7v3" style="width: 400px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/02_todos-component-rendered.png.ca73a89a7b368c65026423357619b351.png"></a>
</p>

<h2>
	إضافة شيفرة HTML الثابتة
</h2>

<p>
	سنبدأ أولًا بتمثيل شيفرة HTML لتطبيقنا لتتمكّن من رؤية الشكل الذي سيبدو عليه، لذا انسخ والصق ما يلي في ملف المكوِّن <code>Todos.svelte</code> ليحل محل المحتوى الموجود مسبقًا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5708_30" style=""><span class="com">&lt;!-- Todos.svelte --&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todoapp stack-large"</span><span class="tag">&gt;</span><span class="pln">

  </span><span class="com">&lt;!-- NewTodo --&gt;</span><span class="pln">
  </span><span class="tag">&lt;form&gt;</span><span class="pln">
    </span><span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"label-wrapper"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-0"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"label__lg"</span><span class="tag">&gt;</span><span class="pln">
        What needs to be done?
      </span><span class="tag">&lt;/label&gt;</span><span class="pln">
    </span><span class="tag">&lt;/h2&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-0"</span><span class="pln"> </span><span class="atn">autocomplete</span><span class="pun">=</span><span class="atv">"off"</span><span class="pln">
      </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"input input__lg"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">disabled</span><span class="pun">=</span><span class="atv">""</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary btn__lg"</span><span class="tag">&gt;</span><span class="pln">
      Add
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;/form&gt;</span><span class="pln">

  </span><span class="com">&lt;!-- Filter --&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"filters btn-group stack-exception"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn toggle-btn"</span><span class="pln"> </span><span class="atn">aria-pressed</span><span class="pun">=</span><span class="atv">"true"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Show</span><span class="tag">&lt;/span&gt;</span><span class="pln">
      </span><span class="tag">&lt;span&gt;</span><span class="pln">All</span><span class="tag">&lt;/span&gt;</span><span class="pln">
      </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">tasks</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn toggle-btn"</span><span class="pln"> </span><span class="atn">aria-pressed</span><span class="pun">=</span><span class="atv">"false"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Show</span><span class="tag">&lt;/span&gt;</span><span class="pln">
      </span><span class="tag">&lt;span&gt;</span><span class="pln">Active</span><span class="tag">&lt;/span&gt;</span><span class="pln">
      </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">tasks</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn toggle-btn"</span><span class="pln"> </span><span class="atn">aria-pressed</span><span class="pun">=</span><span class="atv">"false"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Show</span><span class="tag">&lt;/span&gt;</span><span class="pln">
      </span><span class="tag">&lt;span&gt;</span><span class="pln">Completed</span><span class="tag">&lt;/span&gt;</span><span class="pln">
      </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">tasks</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">

  </span><span class="com">&lt;!-- TodosStatus --&gt;</span><span class="pln">
  </span><span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"list-heading"</span><span class="tag">&gt;</span><span class="pln">2 out of 3 items completed</span><span class="tag">&lt;/h2&gt;</span><span class="pln">

  </span><span class="com">&lt;!-- Todos --&gt;</span><span class="pln">
  </span><span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">role</span><span class="pun">=</span><span class="atv">"list"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-list stack-large"</span><span class="pln"> </span><span class="atn">aria-labelledby</span><span class="pun">=</span><span class="atv">"list-heading"</span><span class="tag">&gt;</span><span class="pln">

    </span><span class="com">&lt;!-- todo-1 (editing mode) --&gt;</span><span class="pln">
    </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-small"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-small"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-1"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-label"</span><span class="tag">&gt;</span><span class="pln">
              New name for 'Create a Svelte starter app'
            </span><span class="tag">&lt;/label&gt;</span><span class="pln">
            </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-1"</span><span class="pln"> </span><span class="atn">autocomplete</span><span class="pun">=</span><span class="atv">"off"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-text"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn todo-cancel"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="tag">&gt;</span><span class="pln">
              Cancel
              </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">renaming Create a Svelte starter app</span><span class="tag">&lt;/span&gt;</span><span class="pln">
            </span><span class="tag">&lt;/button&gt;</span><span class="pln">
            </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary todo-edit"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="tag">&gt;</span><span class="pln">
              Save
              </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">new name for Create a Svelte starter app</span><span class="tag">&lt;/span&gt;</span><span class="pln">
            </span><span class="tag">&lt;/button&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/form&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/li&gt;</span><span class="pln">

    </span><span class="com">&lt;!-- todo-2 --&gt;</span><span class="pln">
    </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-small"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"c-cb"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-2"</span><span class="pln"> </span><span class="atn">checked</span><span class="tag">/&gt;</span><span class="pln">
          </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-2"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-label"</span><span class="tag">&gt;</span><span class="pln">
            Create your first component
          </span><span class="tag">&lt;/label&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn"</span><span class="tag">&gt;</span><span class="pln">
            Edit
            </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Create your first component</span><span class="tag">&lt;/span&gt;</span><span class="pln">
          </span><span class="tag">&lt;/button&gt;</span><span class="pln">
          </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__danger"</span><span class="tag">&gt;</span><span class="pln">
            Delete
            </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Create your first component</span><span class="tag">&lt;/span&gt;</span><span class="pln">
          </span><span class="tag">&lt;/button&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/li&gt;</span><span class="pln">

    </span><span class="com">&lt;!-- todo-3 --&gt;</span><span class="pln">
    </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-small"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"c-cb"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-3"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
          </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"todo-3"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"todo-label"</span><span class="tag">&gt;</span><span class="pln">
            Complete the rest of the tutorial
          </span><span class="tag">&lt;/label&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn"</span><span class="tag">&gt;</span><span class="pln">
            Edit
            </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Complete the rest of the tutorial</span><span class="tag">&lt;/span&gt;</span><span class="pln">
          </span><span class="tag">&lt;/button&gt;</span><span class="pln">
          </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__danger"</span><span class="tag">&gt;</span><span class="pln">
            Delete
            </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Complete the rest of the tutorial</span><span class="tag">&lt;/span&gt;</span><span class="pln">
          </span><span class="tag">&lt;/button&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;/ul&gt;</span><span class="pln">

  </span><span class="tag">&lt;hr</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">

  </span><span class="com">&lt;!-- MoreActions --&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn-group"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary"</span><span class="tag">&gt;</span><span class="pln">Check all</span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary"</span><span class="tag">&gt;</span><span class="pln">Remove completed</span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	تحقّق من الخرج المُصيَّر مرةً أخرى، وسترى شيئًا يشبه ما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="113462" href="https://academy.hsoub.com/uploads/monthly_2022_12/03_unstyled-todo-app.png.5e6cea2dfe72ea64b72e31044aa8afa8.png" rel="" data-fileext="png"><img alt="التحقّق من الخرج المُصيَّر" class="ipsImage ipsImage_thumbnailed" data-fileid="113462" data-unique="pych51f0j" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/03_unstyled-todo-app.png.5e6cea2dfe72ea64b72e31044aa8afa8.png"></a>
</p>

<p>
	يُعَدّ تنسيق شيفرة <a href="https://academy.hsoub.com/programming/html/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-html-r1687/" rel="">HTML</a> السابق ليس جيدًا كما أنه غير مفيد وظيفيًا، ولكن لنلقِ نظرةً على الشيفرة ونرى مدى ارتباطها بالميزات التي نرغب بها:
</p>

<ul>
	<li>
		تسمية أو عنوان Label ومربع نص لإدخال مهام جديدة.
	</li>
	<li>
		ثلاثة أزرار لترشيح المهام حسب حالتها.
	</li>
	<li>
		تسمية label توضّح العدد الإجمالي للمهام والمهام المكتملة.
	</li>
	<li>
		قائمة غير مرتبة تحتوي على عنصر قائمة لكل مهمة.
	</li>
	<li>
		يحتوي عنصر القائمة عند تعديل المهمة على حقل إدخال وزرَين لإلغاء التعديلات أو حفظها.
	</li>
	<li>
		إذا لم تكن المهمة قيد التعديل، فهناك مربع اختيار لضبط حالة المهمة المكتملة وزرَين لتعديل المهمة أو حذفها.
	</li>
	<li>
		يوجد زران لتحديد أو إلغاء تحديد جميع المهام وإزالة المهام المكتملة.
	</li>
</ul>

<p>
	سنعمل في المقالات اللاحقة على تشغيل جميع هذه الميزات.
</p>

<h3>
	ميزات سهولة الوصول Accessibility لقائمة المهام
</h3>

<p>
	لاحظ وجود بعض السمات غير المعتادة مثل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5708_34" style=""><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn toggle-btn"</span><span class="pln"> </span><span class="atn">aria-pressed</span><span class="pun">=</span><span class="atv">"true"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">Show</span><span class="tag">&lt;/span&gt;</span><span class="pln">
  </span><span class="tag">&lt;span&gt;</span><span class="pln">All</span><span class="tag">&lt;/span&gt;</span><span class="pln">
  </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"visually-hidden"</span><span class="tag">&gt;</span><span class="pln">tasks</span><span class="tag">&lt;/span&gt;</span><span class="pln">
</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	تخبر السمة <code>aria-pressed</code> التقنيات المساعدة مثل قارئات الشاشة أنّ الزر يمكن أن يكون في إحدى الحالتين: <code>pressed</code> أو <code>unpressed</code> مثل القول بأن الزر في وضع التشغيل أو الإيقاف، ويعني ضبط القيمة <code>true</code> أنّ الزر مضغوط افتراضيًا.
</p>

<p>
	ليس للصنف <code>visually-hidden</code> أيّ تأثير حتى الآن، لأننا لم نضمّن أيّ ملف <a href="https://academy.hsoub.com/programming/css/%d8%aa%d8%b9%d8%b1%d9%91%d9%81-%d8%b9%d9%84%d9%89-%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d8%a7%d8%aa-css-r70/" rel="">CSS</a>، وسيُخفَى أيّ عنصر موجود في هذا الصنف عن المستخدِمين المبصرين وسيظل متاحًا لمستخدِمي قارئات الشاشة بمجرد أن نضع التنسيق في مكانه، لأن هذه الكلمات لا يحتاجها المستخدِمون المبصرون، وإنما تُستخدَم لتقديم مزيد من المعلومات حول ما يفعله الزر لمستخدِمي قارئات الشاشة الذين ليس لديهم القدرة البصرية لمساعدتهم.
</p>

<p>
	كما يمكنك العثور على <a href="https://wiki.hsoub.com/HTML/ul" rel="external">عنصر &lt;ul&gt;</a> التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5708_38" style=""><span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">role</span><span class="pun">=</span><span class="atv">"list"</span><span class="pln"> </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"todo-list stack-large"</span><span class="pln"> </span><span class="atn">aria-labelledby</span><span class="pun">=</span><span class="atv">"list-heading"</span><span class="tag">&gt;</span></pre>

<p>
	تساعد السمة <code>role</code> التقنيات المساعدة في توضيح نوع القيمة الدلالية للعنصر أو ما هو الغرض منه، إذ يُعامَل العنصر <code>&lt;ul&gt;</code> بوصفه قائمةً افتراضيًا، ولكن ستؤدي التنسيقات التي نريد إضافتها إلى تعطيل هذه الوظيفة، ولكن سيعيد هذا الدور معنى القائمة إلى العنصر <code>&lt;ul&gt;</code>.
</p>

<p>
	تخبر السمة <code>aria-labelledby</code> التقنيات المساعدة بأننا نتعامل مع <a href="https://wiki.hsoub.com/HTML/h1-h6" rel="external">العنصر &lt;h2&gt;</a> مع معرِّف <code>id</code> عنوان القائمة <code>list-heading</code> بوصفه التسمية التي تشرح الغرض من القائمة الموجودة تحتها، إذ يعطي هذا الارتباط القائمةَ سياقًا مفيدًا، مما يساعد مستخدِمي قارئات الشاشة على فهم الغرض منها بصورة أفضل.
</p>

<h2>
	دعم إطار عمل Svelte لسهولة الوصول
</h2>

<p>
	يركّز إطار Svelte على سهولة الوصول أو الشمولية Accessibility، والهدف هو تشجيع المطورين على كتابة المزيد من الشيفرة البرمجية الشاملة افتراضيًا، وبما أنّ إطار Svelte يُعَدّ مصرِّفًا، فيمكنه تحليل قوالب HTML بطريقة ساكنة لتوفير تحذيرات متعلقة بسهولة الوصول عند تصريف المكونات.
</p>

<p>
	لا يُعَدّ عملية تطبيق مبادئ سهولة الوصول -التي تُختصَر إلى a11y- أمرًا سهلًا دائمًا، ولكن سيساعدك إطار Svelte من خلال تحذيرك إذا كتبت شيفرة HTML لا تراعي تلك المبادئ، فإذا أضفنا <a href="https://wiki.hsoub.com/HTML/img" rel="external">العنصر &lt;img&gt;</a> مثلًا إلى المكوِّن <code>todos.svelte</code> بدون الخاصية <code>alt</code> المقابلة له كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7149_7" style=""><span class="tag">&lt;h1&gt;</span><span class="pln">Svelte To-Do list</span><span class="tag">&lt;/h1&gt;</span><span class="pln">

</span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"32"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"88"</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://www.w3.org/WAI/wcag2A"</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	فسيعطي المصرِّف التحذير التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5708_44" style=""><span class="pun">(!)</span><span class="pln"> </span><span class="typ">Plugin</span><span class="pln"> svelte</span><span class="pun">:</span><span class="pln"> A11y</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">img</span><span class="pun">&gt;</span><span class="pln"> element should have an alt attribute
src</span><span class="pun">/</span><span class="pln">components</span><span class="pun">/</span><span class="typ">Todos</span><span class="pun">.</span><span class="pln">svelte
</span><span class="lit">1</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Svelte</span><span class="pln"> </span><span class="typ">To</span><span class="pun">-</span><span class="typ">Do</span><span class="pln"> list</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="lit">2</span><span class="pun">:</span><span class="pln">
</span><span class="lit">3</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">img height</span><span class="pun">=</span><span class="str">"32"</span><span class="pln"> width</span><span class="pun">=</span><span class="str">"88"</span><span class="pln"> src</span><span class="pun">=</span><span class="str">"https://www.w3.org/WAI/wcag2A"</span><span class="pun">&gt;</span><span class="pln">
   </span><span class="pun">^</span><span class="pln">
created </span><span class="kwd">public</span><span class="pun">/</span><span class="pln">build</span><span class="pun">/</span><span class="pln">bundle</span><span class="pun">.</span><span class="pln">js in </span><span class="lit">220ms</span><span class="pln">

</span><span class="pun">[</span><span class="lit">2020</span><span class="pun">-</span><span class="lit">07</span><span class="pun">-</span><span class="lit">15</span><span class="pln"> </span><span class="lit">04</span><span class="pun">:</span><span class="lit">07</span><span class="pun">:</span><span class="lit">43</span><span class="pun">]</span><span class="pln"> waiting </span><span class="kwd">for</span><span class="pln"> changes</span><span class="pun">…</span></pre>

<p>
	كما يمكن لمحرر الشيفرة عرض هذا التحذير حتى قبل استدعاء المصرِّف كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="113463" href="https://academy.hsoub.com/uploads/monthly_2022_12/04_svelte-accessibility-support.png.cbcdc1d1dc00aab6ebe90752e0e7cead.png" rel="" data-fileext="png"><img alt="عرض محرر الشيفرة التحذير حتى قبل استدعاء المصرِّف" class="ipsImage ipsImage_thumbnailed" data-fileid="113463" data-unique="e0solitnk" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/04_svelte-accessibility-support.png.cbcdc1d1dc00aab6ebe90752e0e7cead.png"></a>
</p>

<p>
	يمكنك إخبار إطار عمل Svelte بتجاهل هذا التحذير للكتلة التالية من شيفرة HTML بتعليق يبدأ بعبارة <code>svelte-ignore</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5708_48" style=""><span class="com">&lt;!-- svelte-ignore a11y-missing-attribute --&gt;</span><span class="pln">
</span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"32"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"88"</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://www.w3.org/WAI/wcag2A"</span><span class="tag">&gt;</span></pre>

<p>
	<strong>ملاحظة</strong>: يمكنك باستخدام المحرّر VSCode إضافة تعليق التجاهل هذا تلقائيًا بالنقر على الرابط "Quick fix…‎" أو بالضغط على الاختصار <code>Ctrl + .‎</code>.
</p>

<p>
	إذا أردت تعطيل هذا التحذير، فيمكنك إضافة المعالج <code>onwarn</code> إلى الملف rollup.config.js ضمن إعداد الإضافة <code>Svelte</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5708_50" style=""><span class="pln">plugins</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  svelte</span><span class="pun">({</span><span class="pln">
    dev</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">production</span><span class="pun">,</span><span class="pln">
    css</span><span class="pun">:</span><span class="pln"> css </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      css</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">'public/build/bundle.css'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="com">// Warnings are normally passed straight to Rollup. You can</span><span class="pln">
    </span><span class="com">// optionally handle them here, for example to squelch</span><span class="pln">
    </span><span class="com">// warnings with a particular code</span><span class="pln">
    onwarn</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">warning</span><span class="pun">,</span><span class="pln"> handler</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// e.g. I don't care about screen readers -&gt; please DON'T DO THIS!!!</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">warning</span><span class="pun">.</span><span class="pln">code </span><span class="pun">===</span><span class="pln"> </span><span class="str">'a11y-missing-attribute'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">

      </span><span class="com">// let Rollup handle all other warnings normally</span><span class="pln">
      handler</span><span class="pun">(</span><span class="pln">warning</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}),</span><span class="pln">

  </span><span class="pun">...</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	تُنفَّذ هذه التحذيرات في المصرِّف نفسه حسب التصميم وليس على أساس إضافة يمكن أن تختار إضافتها إلى مشروعك، كما تكمن الفكرة في التحقق من وجود مشاكل سهولة الوصول a11y في الشيفرة افتراضيًا والسماح بإلغاء تحذيرات معينة.
</p>

<p>
	<strong>ملاحظة</strong>: لا يجب تعطيل هذه التحذيرات إلا إذا كانت لديك أسباب وجيهة لذلك مثل تعطيلها أثناء إنشاء نموذج أولي prototype سريع، إذ يجب أن تجعل صفحاتك قابلةً للوصول إلى أوسع قاعدة ممكنة من المستخدِمين.
</p>

<p>
	قواعد الشمولية التي تحقق منها إطار عمل Svelte مأخوذة من الإضافة <a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#supported-rules" rel="external nofollow">eslint-plugin-jsx-a11y</a>، وهي إضافة من ESLint توفِّر فحوصات ساكنة للعديد من قواعد سهولة الوصول على عناصر JSX، كما يهدف إطار Svelte إلى تنفيذ كل من هذه القواعد في مصرِّفه، وقد نُقِل معظمها إلى Svelte فعليًا، بالإضافة إلى أنه يمكنك على GitHub <a href="https://github.com/sveltejs/svelte/issues/820" rel="external nofollow">معرفة فحوصات الشمولية التي لا تزال مفقودة</a>، ويمكنك التحقق من معنى كل قاعدة من خلال النقر على رابطها الخاص.
</p>

<h2>
	تنسيق التطبيق
</h2>

<p>
	لنجعل قائمة المهام تبدو أفضل قليلًا، لذا استبدل محتويات الملف public/global.css بما يلي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_5708_52" style=""><span class="com">/* RESETS */</span><span class="pln">
</span><span class="pun">*,</span><span class="pln">
</span><span class="pun">*::</span><span class="pln">before</span><span class="pun">,</span><span class="pln">
</span><span class="pun">*::</span><span class="pln">after </span><span class="pun">{</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">*:</span><span class="pln">focus </span><span class="pun">{</span><span class="pln">
  outline</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3px</span><span class="pln"> dashed </span><span class="com">#228bec;</span><span class="pln">
  outline</span><span class="pun">-</span><span class="pln">offset</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
html </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">:</span><span class="pln"> </span><span class="lit">62.5</span><span class="pun">%</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">1.15</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
h1</span><span class="pun">,</span><span class="pln">
h2 </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
ul </span><span class="pun">{</span><span class="pln">
  list</span><span class="pun">-</span><span class="pln">style</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
button </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
  overflow</span><span class="pun">:</span><span class="pln"> visible</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> transparent</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> normal</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">appearance</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
button</span><span class="pun">::-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">focus</span><span class="pun">-</span><span class="pln">inner </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
button</span><span class="pun">,</span><span class="pln">
input</span><span class="pun">,</span><span class="pln">
optgroup</span><span class="pun">,</span><span class="pln">
</span><span class="kwd">select</span><span class="pun">,</span><span class="pln">
textarea </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.15</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
button</span><span class="pun">,</span><span class="pln">
input </span><span class="pun">{</span><span class="pln">
  overflow</span><span class="pun">:</span><span class="pln"> visible</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
input</span><span class="pun">[</span><span class="pln">type</span><span class="pun">=</span><span class="str">"text"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
body </span><span class="pun">{</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  max</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">68rem</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.6rem</span><span class="pun">/</span><span class="lit">1.25</span><span class="pln"> </span><span class="typ">Arial</span><span class="pun">,</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#f5f5f5;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#4d4d4d;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="lit">@media</span><span class="pln"> screen </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln">min</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">620px</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  body </span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.9rem</span><span class="pun">;</span><span class="pln">
    line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.31579</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">/*END RESETS*/</span><span class="pln">

</span><span class="com">/* GLOBAL STYLES */</span><span class="pln">
</span><span class="pun">.</span><span class="pln">form</span><span class="pun">-</span><span class="kwd">group</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">type</span><span class="pun">=</span><span class="str">"text"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inline</span><span class="pun">-</span><span class="pln">block</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.4rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn </span><span class="pun">{</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.8rem</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> </span><span class="lit">0.7rem</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.2rem</span><span class="pln"> solid </span><span class="com">#4d4d4d;</span><span class="pln">
  cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">transform</span><span class="pun">:</span><span class="pln"> capitalize</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn</span><span class="pun">.</span><span class="pln">toggle</span><span class="pun">-</span><span class="pln">btn </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#d3d3d3;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn</span><span class="pun">.</span><span class="pln">toggle</span><span class="pun">-</span><span class="pln">btn</span><span class="pun">[</span><span class="pln">aria</span><span class="pun">-</span><span class="pln">pressed</span><span class="pun">=</span><span class="str">"true"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">decoration</span><span class="pun">:</span><span class="pln"> underline</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#4d4d4d;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn__danger </span><span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#ca3c3c;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#bd2130;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn__filter </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> lightgrey</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn__primary </span><span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#000;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn__primary</span><span class="pun">:</span><span class="pln">disabled </span><span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> darkgrey</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:#</span><span class="lit">565656</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn</span><span class="pun">-</span><span class="kwd">group</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
  justify</span><span class="pun">-</span><span class="pln">content</span><span class="pun">:</span><span class="pln"> space</span><span class="pun">-</span><span class="pln">between</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn</span><span class="pun">-</span><span class="kwd">group</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  flex</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">49</span><span class="pun">%;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn</span><span class="pun">-</span><span class="kwd">group</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.8rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">label</span><span class="pun">-</span><span class="pln">wrapper </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  flex</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">visually</span><span class="pun">-</span><span class="pln">hidden </span><span class="pun">{</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> absolute </span><span class="pun">!</span><span class="pln">important</span><span class="pun">;</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">;</span><span class="pln">
  overflow</span><span class="pun">:</span><span class="pln"> hidden</span><span class="pun">;</span><span class="pln">
  clip</span><span class="pun">:</span><span class="pln"> rect</span><span class="pun">(</span><span class="lit">1px</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">);</span><span class="pln">
  clip</span><span class="pun">:</span><span class="pln"> rect</span><span class="pun">(</span><span class="lit">1px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">);</span><span class="pln">
  white</span><span class="pun">-</span><span class="pln">space</span><span class="pun">:</span><span class="pln"> nowrap</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">[</span><span class="kwd">class</span><span class="pun">*=</span><span class="str">"stack"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">stack</span><span class="pun">-</span><span class="pln">small </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.25rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">stack</span><span class="pun">-</span><span class="pln">large </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2.5rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="lit">@media</span><span class="pln"> screen </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln">min</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">550px</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">stack</span><span class="pun">-</span><span class="pln">small </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.4rem</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">stack</span><span class="pun">-</span><span class="pln">large </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2.8rem</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">stack</span><span class="pun">-</span><span class="pln">exception </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.2rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">/* END GLOBAL STYLES */</span><span class="pln">

</span><span class="pun">.</span><span class="pln">todoapp </span><span class="pun">{</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2rem</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">4rem</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> </span><span class="lit">4px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0.2</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2.5rem</span><span class="pln"> </span><span class="lit">5rem</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0.1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="lit">@media</span><span class="pln"> screen </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln">min</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">550px</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">todoapp </span><span class="pun">{</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4rem</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">todoapp </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  max</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50rem</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">todoapp </span><span class="pun">&gt;</span><span class="pln"> form </span><span class="pun">{</span><span class="pln">
  max</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">todoapp </span><span class="pun">&gt;</span><span class="pln"> h1 </span><span class="pun">{</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
  max</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">label__lg </span><span class="pun">{</span><span class="pln">
  line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.01567</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">300</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.8rem</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">input__lg </span><span class="pun">{</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2rem</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> solid </span><span class="com">#000;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">input__lg</span><span class="pun">:</span><span class="pln">focus </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#4d4d4d;</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> inset </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">[</span><span class="kwd">class</span><span class="pun">*=</span><span class="str">"__lg"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inline</span><span class="pun">-</span><span class="pln">block</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.9rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">[</span><span class="kwd">class</span><span class="pun">*=</span><span class="str">"__lg"</span><span class="pun">]:</span><span class="kwd">not</span><span class="pun">(:</span><span class="kwd">last</span><span class="pun">-</span><span class="pln">child</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="lit">@media</span><span class="pln"> screen </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln">min</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">620px</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">[</span><span class="kwd">class</span><span class="pun">*=</span><span class="str">"__lg"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2.4rem</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">filters </span><span class="pun">{</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> unset </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">/* Todo item styles */</span><span class="pln">
</span><span class="pun">.</span><span class="pln">todo </span><span class="pun">{</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
  flex</span><span class="pun">-</span><span class="pln">direction</span><span class="pun">:</span><span class="pln"> row</span><span class="pun">;</span><span class="pln">
  flex</span><span class="pun">-</span><span class="pln">wrap</span><span class="pun">:</span><span class="pln"> wrap</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">todo </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  flex</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">text </span><span class="pun">{</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  min</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4.4rem</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.4rem</span><span class="pln"> </span><span class="lit">0.8rem</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> solid </span><span class="com">#565656;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">text</span><span class="pun">:</span><span class="pln">focus </span><span class="pun">{</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> inset </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">/* CHECKBOX STYLES */</span><span class="pln">
</span><span class="pun">.</span><span class="pln">c</span><span class="pun">-</span><span class="pln">cb </span><span class="pun">{</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Arial</span><span class="pun">,</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">400</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.6rem</span><span class="pun">;</span><span class="pln">
  line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.25</span><span class="pun">;</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
  min</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">44px</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40px</span><span class="pun">;</span><span class="pln">
  clear</span><span class="pun">:</span><span class="pln"> left</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">c</span><span class="pun">-</span><span class="pln">cb </span><span class="pun">&gt;</span><span class="pln"> label</span><span class="pun">::</span><span class="pln">before</span><span class="pun">,</span><span class="pln">
</span><span class="pun">.</span><span class="pln">c</span><span class="pun">-</span><span class="pln">cb </span><span class="pun">&gt;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
  top</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2px</span><span class="pun">;</span><span class="pln">
  left</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2px</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">44px</span><span class="pun">;</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">44px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">c</span><span class="pun">-</span><span class="pln">cb </span><span class="pun">&gt;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
  cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
  z</span><span class="pun">-</span><span class="pln">index</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">c</span><span class="pun">-</span><span class="pln">cb </span><span class="pun">&gt;</span><span class="pln"> label </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inline</span><span class="pun">-</span><span class="pln">block</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8px</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln">
  cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
  touch</span><span class="pun">-</span><span class="pln">action</span><span class="pun">:</span><span class="pln"> manipulation</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">c</span><span class="pun">-</span><span class="pln">cb </span><span class="pun">&gt;</span><span class="pln"> label</span><span class="pun">::</span><span class="pln">before </span><span class="pun">{</span><span class="pln">
  content</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> solid currentColor</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> transparent</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">c</span><span class="pun">-</span><span class="pln">cb </span><span class="pun">&gt;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pun">]:</span><span class="pln">focus </span><span class="pun">+</span><span class="pln"> label</span><span class="pun">::</span><span class="pln">before </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4px</span><span class="pun">;</span><span class="pln">
  outline</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3px</span><span class="pln"> dashed </span><span class="com">#228bec;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">c</span><span class="pun">-</span><span class="pln">cb </span><span class="pun">&gt;</span><span class="pln"> label</span><span class="pun">::</span><span class="pln">after </span><span class="pun">{</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> content</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
  content</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
  top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">11px</span><span class="pun">;</span><span class="pln">
  left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">9px</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">18px</span><span class="pun">;</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7px</span><span class="pun">;</span><span class="pln">
  transform</span><span class="pun">:</span><span class="pln"> rotate</span><span class="pun">(-</span><span class="lit">45deg</span><span class="pun">);</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> solid</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">top</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> transparent</span><span class="pun">;</span><span class="pln">
  opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> transparent</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">c</span><span class="pun">-</span><span class="pln">cb </span><span class="pun">&gt;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pun">]:</span><span class="kwd">checked</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> label</span><span class="pun">::</span><span class="pln">after </span><span class="pun">{</span><span class="pln">
  opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يبدو كل شيء الآن أفضل كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="113464" href="https://academy.hsoub.com/uploads/monthly_2022_12/05_styled-todo-app.png.2b3bead06fa22ead28b123e6a4828da5.png" rel="" data-fileext="png"><img alt="نتيجة تنسيق قائمة المهام" class="ipsImage ipsImage_thumbnailed" data-fileid="113464" data-unique="sw6focfml" style="width: 473px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/05_styled-todo-app.thumb.png.c20e197bd590604d08d7d64fbe632fe7.png"></a>
</p>

<p>
	يمكنك الوصول إلى نسختك من مستودعنا على النحو التالي لمعرفة حالة الشيفرة، كما يجب أن تكون في نهاية هذا المقال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5708_55" style=""><span class="pln">cd mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">03</span><span class="pun">-</span><span class="pln">adding</span><span class="pun">-</span><span class="pln">dynamic</span><span class="pun">-</span><span class="pln">behavior</span></pre>

<p>
	أو يمكنك تنزيل محتوى المجلد مباشرةً باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5708_58" style=""><span class="pln">npx degit opensas</span><span class="pun">/</span><span class="pln">mdn</span><span class="pun">-</span><span class="pln">svelte</span><span class="pun">-</span><span class="pln">tutorial</span><span class="pun">/</span><span class="lit">03</span><span class="pun">-</span><span class="pln">adding</span><span class="pun">-</span><span class="pln">dynamic</span><span class="pun">-</span><span class="pln">behavior</span></pre>

<p>
	تذكَّر تشغيل الأمر <code>npm install &amp;&amp; npm run dev</code> لبدء تشغيل تطبيقك في وضع التطوير، فإذا أردت متابعتنا، فابدأ بكتابة الشيفرة <a href="https://svelte.dev/repl/c862d964d48d473ca63ab91709a0a5a0?version=3.23.2" rel="external nofollow">باستخدام الأداة REPL</a>.
</p>

<h2>
	الخلاصة
</h2>

<p>
	بدأ تطبيق قائمة المهام في التبلور مع تطبيق شيفرة HTML وشيفرة التنسيق CSS، وأصبح كل شيء جاهزًا لنتمكّن من التركيز على الميزات التي يجب تطبيقها.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_Todo_list_beginning" rel="external nofollow">Starting our Svelte to-do list app</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D8%AF%D8%A1-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-svelte-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-r1810/" rel="">بدء استخدام إطار العمل Svelte لبناء تطبيقات ويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/react/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-react-r1570/" rel="">إنشاء تطبيق قائمة مهام باستخدام React</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/laravel/%d8%a5%d9%86%d8%b4%d8%a7%d8%a1-%d8%aa%d8%b7%d8%a8%d9%8a%d9%82-todo-list-%d8%a8%d8%b3%d9%8a%d8%b7-%d8%a8%d8%a7%d8%b3%d8%aa%d8%ae%d8%af%d8%a7%d9%85-laravel-5-%d8%a7%d9%84%d8%ac%d8%b2%d8%a1-%d8%a7%d9%84%d8%a3%d9%88%d9%84-r149/" rel="">إنشاء تطبيق Todo List بسيط باستخدام Laravel 5 - الجزء الأول</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1811</guid><pubDate>Wed, 07 Dec 2022 16:07:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x642;&#x627;&#x631;&#x646;&#x629; &#x627;&#x644;&#x634;&#x627;&#x645;&#x644;&#x629; &#x628;&#x64A;&#x646; Angular &#x648; React.js &#x648; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84%D8%A9-%D8%A8%D9%8A%D9%86-angular-%D9%88-reactjs-%D9%88-vuejs-r2071/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_08/aca-(1).png.7669f995bf8d6b62931a266a3a626fa9.png" /></p>
<p>
	مما لا شك فيه أن لغة البرمجة جافاسكربت JavaScript حاليًا من أهم لغات البرمجة المستخدمة في <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%85%D9%8A%D8%A9-frontend-web-development/" rel="">تطوير الواجهات الأمامية FrontEnd</a> وتطبيقات الويب وتطبيقات الجوال ويوجد عدة أطر عمل Frameworks في لغة برمجة جافاسكربت JavaScript، سنتحدث في هذا الفيديو عن أشهرها وهي أنجولار Angular و ريأكت React.js و فيو Vue.js، وسنتحدث عن تاريخها واستخداماتها في مختلف المشاريع البرمجية ومميزاتها وتوافر فرص العمل لكل منها.
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="603" id="ips_uid_7312_16" src="https://academy.hsoub.com/applications/core/interface/index.html" title="المقارنة الشاملة بين Angular و React.js و Vue.js" width="1072" data-embed-src="https://www.youtube.com/embed/iGLoINDH5b0"></iframe>
</p>

<p>
	إذا أردت التعرف أكثر على جافاسكربت وأطر العمل فيها، فننصحك بالانضمام إلى <a href="https://academy.hsoub.com/learn/javascript-application-development" rel="">دورة تطوير التطبيقات باستخدام لغة JavaScript</a>، ولا تنسَ الاستعانة خلال رحلة تعلمك وعملك بتوثيقات <a href="https://wiki.hsoub.com/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" rel="external">موسوعة حسوب</a> المجانية. وإذا أردت متابعة المعلومات البرمجية العلمية مكتوبة فيمكنك الاطلاع على <a href="https://academy.hsoub.com/programming/" rel="">قسم البرمجة في أكاديمية حسوب</a>، كما يمكنك متابعة جديد الفيديوهات التقنية المتاحة على <a href="https://www.youtube.com/@HsoubAcademy" rel="external nofollow">يوتيوب أكاديمية حسوب</a> مجانًا.
</p>
]]></description><guid isPermaLink="false">2071</guid><pubDate>Tue, 06 Dec 2022 15:00:00 +0000</pubDate></item></channel></rss>
