<?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/2/?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>&#x625;&#x646;&#x62C;&#x627;&#x632; &#x648;&#x627;&#x62C;&#x647;&#x629; &#x628;&#x631;&#x645;&#x62C;&#x64A;&#x629; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A; &#x62A;&#x639;&#x62A;&#x645;&#x62F; &#x639;&#x644;&#x649; &#x627;&#x644;&#x648;&#x639;&#x648;&#x62F;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A5%D9%86%D8%AC%D8%A7%D8%B2-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%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-%D8%AA%D8%B9%D8%AA%D9%85%D8%AF-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%B9%D9%88%D8%AF-r2348/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_06/--------.png.36ab1585f571d83b3ac68332e326c4ea.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%88%D8%B9%D9%88%D8%AF-promises-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2341/" rel="">المقال السابق</a> طريقة استخدام واجهات برمجة التطبيقات التي تعيد الوعود promises، وسنتحدث في هذا المقال عن تعريف الواجهات البرمجية التي تعيد وعودًا في لغة البرمجة جافا سكريبت، ونلقي نظرة على كيفية إنجاز هذه الواجهات البرمجية بأنفسنا، وعلى الرغم من أن مهمة كهذه ليست شائعة الاستخدام كثيرًا لكن من المفيد لك معرفتها.
</p>

<p>
	ملاحظة: عند تنفيذ واجهة برمجة تطبيقات معتمدة على الوعود promise-based <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> ستحتاج لأن نغلّف عملية غير متزامنة (مثل اﻷحداث events، أو دوال رد النداء callbacks، أو نموذج يعمل على تمرير الرسائل message-passing model) وسيكون عليك هيكلة كائن Promise للتعامل مع حالات نجاح تنفيذ هذه العملية resolve أو إخفاقها reject.
</p>

<h2 id="alarm">
	تنفيذ الواجهة البرمجية <code>()alarm</code>
</h2>

<p>
	ما سنفعله في هذا المثال هو إنجاز واجهة برمجية لمنبّه تُدعى <code>()alarm</code>. تقبل هذه الواجهة وسيطًا هو اسم الشخص الذي ستوقظه كما تأخذ وسيطًا آخر هي الفترة الزمنية التي ينتظرها المنبه بالميلي ثانية قبل إيقاظ الشخص. بعد ذلك تُرسل الدالة الرسالة "Wake up" (أي استيقظ) يليها اسم الشخص.
</p>

<h3 id="settimeout">
	تغليف الدالة <code>()setTimeout</code>
</h3>

<p>
	نستخدم الواجهة <code>()setTimeout</code> في إنجاز واجهتنا <code>()alarm</code>، وتأخذ هذه الواجهة وسيطين: دالة تستدعيها عند بلوغ زمن التنبيه، واﻵخر زمن التنبيه بالميلي ثانية. وعندما تُستدعى الواجهة <code>()setTimeout</code>، تبدأ بالعد وصولًا إلى زمن التنبيه وتستدعي عندها الدالة التي مررناها إليها.
</p>

<p>
	نستدعي في مثالنا التالي الدالة <code>()setTimeout</code> مع وسيطيها دالة رد النداء وزمن التنبيه الذي سيكون 1000 ميلي ثانية. إليك شيفرة HTML:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5878_6" style=""><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"set-alarm"</span><span class="tag">&gt;</span><span class="pln">Set alarm</span><span class="tag">&lt;/button&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">"output"</span><span class="tag">&gt;&lt;/div&gt;</span></pre>

<p>
	ثم شيفرة جافا سكريبت:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5878_8" style=""><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><span class="pln">
</span><span class="kwd">const</span><span class="pln"> button </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">"#set-alarm"</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> setAlarm</span><span class="pun">()</span><span class="pln"> </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"> </span><span class="pun">{</span><span class="pln">
    output</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Wake up!"</span><span class="pun">;</span><span class="pln">
 </span><span class="pun">},</span><span class="pln"> </span><span class="lit">1000</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"> setAlarm</span><span class="pun">);</span></pre>

<p>
	إليك نتيجة التنفيذ:
</p>

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

<h3 id="promise">
	الدالة البانية <code>()Promise</code>
</h3>

<p>
	تُعيد الدالة وعدًا <code>Promise</code> يُنجز عندما ينقضي الوقت المخصص للمنبّه، ويمرر الرسالة إلى معالج <code>()then</code> بينما يُرفض الوعد إن كان زمن التنبيه سالبًا.
</p>

<p>
	إن المفتاح الرئيسي للعمل هنا هي الدالة البانية <code>()Promise</code> التي تأخذ دالة استدعاء كوسيط لها وندعوها دالة منفّذة <code>executer</code> وعليك كتابة شيفرة هذه الدالة عند إنشاء وعد جديد. وتأخذ الدالة المنفذة دالتين كوسيط لها تُدعيان تقليديًا الدالة <code>resolve</code> والدالة  <code>reject</code>. تستدعي الدالة المنفذة الدالة غير المتزامنة فإن أنجز الوعد ستُستدعى الدالة <code>resolve</code> وإن أخفق تُستدعى الدالة <code>reject</code>. إما إذا رمت الدالة المنفذة خطأً، ستُستدعى <code>reject</code> تلقائيًا. باﻹمكان تمرير أية قيم إلى الدالتين <code>resolve</code> و <code>reject</code>.
</p>

<p>
	لذا بإمكانك كتابة شيفرة الواجهة <code>()alarm</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5878_10" style=""><span class="kwd">function</span><span class="pln"> alarm</span><span class="pun">(</span><span class="pln">person</span><span class="pun">,</span><span class="pln"> delay</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">Promise</span><span class="pun">((</span><span class="pln">resolve</span><span class="pun">,</span><span class="pln"> reject</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">delay </span><span class="pun">&lt;</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="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">"Alarm delay must not be negative"</span><span class="pun">);</span><span class="pln">
    </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"> </span><span class="pun">{</span><span class="pln">
     resolve</span><span class="pun">(`</span><span class="typ">Wake</span><span class="pln"> up</span><span class="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">person</span><span class="pun">}!`);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln"> delay</span><span class="pun">);</span><span class="pln">
 </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُنشئ الدالة السابقة وعدًا <code>Promise</code> وتعيده، وضمن الدالة المنفذة:
</p>

<ul>
	<li>
		نتحقق من قيمة زمن التنبيه <code>delay</code> حتى لا تكون سالبة.
	</li>
	<li>
		نستدعي الدالة <code>()setTimeout</code> ونمرر لها القيمة <code>delay</code>، ومن ثم تُستدعى دالة رد النداء الموجودة ضمن الدالة السابقة عند انقضاء الوقت المحدد ومن ثم تٌستدعى الدالة <code>resolve</code> بعد أن نمرر لها الرسالة <code>"!Wake up"</code>.
	</li>
</ul>

<h2 id="alarm-1">
	استخدام الواجهة البرمجية <code>()alarm</code>
</h2>

<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%88%D8%B9%D9%88%D8%AF-promises-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2341/" rel="">المقال السابق</a>. إذ نستطيع استدعاء الواجهة <code>()alarm</code> ومن ثم نستدعي <code>()then</code> و <code>()catch</code> لكائن الوعد الذي تعيده للتعامل مع حالتي إنجاز الوعد أو رفضه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5878_14" style=""><span class="kwd">const</span><span class="pln"> name </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">"#name"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> delay </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">"#delay"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> button </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">"#set-alarm"</span><span class="pun">);</span><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><span class="pln">

</span><span class="kwd">function</span><span class="pln"> alarm</span><span class="pun">(</span><span class="pln">person</span><span class="pun">,</span><span class="pln"> delay</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">Promise</span><span class="pun">((</span><span class="pln">resolve</span><span class="pun">,</span><span class="pln"> reject</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">delay </span><span class="pun">&lt;</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="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">"Alarm delay must not be negative"</span><span class="pun">);</span><span class="pln">
    </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"> </span><span class="pun">{</span><span class="pln">
     resolve</span><span class="pun">(`</span><span class="typ">Wake</span><span class="pln"> up</span><span class="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">person</span><span class="pun">}!`);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln"> delay</span><span class="pun">);</span><span class="pln">
 </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"> </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">
 alarm</span><span class="pun">(</span><span class="pln">name</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> delay</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">then</span><span class="pun">((</span><span class="pln">message</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">output</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> message</span><span class="pun">))</span><span class="pln">
    </span><span class="pun">.</span><span class="kwd">catch</span><span class="pun">((</span><span class="pln">error</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">output</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">Couldn</span><span class="str">'</span><span class="pln">t </span><span class="kwd">set</span><span class="pln"> alarm</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">error</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="250" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/MWdEvMV?default-tab=result" style="width: 100%;" title="promise-based API2">See the Pen promise-based API2 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<p>
	جرب تحديد قيم مختلفة لكل من <code>person</code> و <code>delay</code> وحاول تمرير قيم <code>delay</code> سالبة وراقب الخرج الناتج.
</p>

<h2 id="asyncawaitalarm">
	استخدام التعليمين <code>async</code> و <code>await</code> مع الواجهة البرمجية <code>alarm()‎</code>
</h2>

<p>
	طالما أن الواجهة <code>()alarm</code>تعيد وعدًا، نستطيع أن نطبق عليه ما يُطبق على أي وعد آخر، مثل ربطه ضمن سلسلة وعود promise-chain أو استخدام <code>()all.</code> وكذلك <code>wait</code>/<code>async</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5878_19" style=""><span class="kwd">const</span><span class="pln"> name </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">"#name"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> delay </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">"#delay"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> button </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">"#set-alarm"</span><span class="pun">);</span><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><span class="pln">

</span><span class="kwd">function</span><span class="pln"> alarm</span><span class="pun">(</span><span class="pln">person</span><span class="pun">,</span><span class="pln"> delay</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">Promise</span><span class="pun">((</span><span class="pln">resolve</span><span class="pun">,</span><span class="pln"> reject</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">delay </span><span class="pun">&lt;</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="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">"Alarm delay must not be negative"</span><span class="pun">);</span><span class="pln">
    </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"> </span><span class="pun">{</span><span class="pln">
     resolve</span><span class="pun">(`</span><span class="typ">Wake</span><span class="pln"> up</span><span class="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">person</span><span class="pun">}!`);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln"> delay</span><span class="pun">);</span><span class="pln">
 </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"> </span><span class="kwd">async</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">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> message </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</span><span class="pln"> alarm</span><span class="pun">(</span><span class="pln">name</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
    output</span><span class="pun">.</span><span class="pln">textContent </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="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    output</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">Couldn</span><span class="str">'</span><span class="pln">t </span><span class="kwd">set</span><span class="pln"> alarm</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">error</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="250" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/vYweJoE?default-tab=result" style="width: 100%;" title="promise-based API3">See the Pen promise-based API3 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<h2>
	الخلاصة
</h2>

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

<p>
	ترجمة -وبتصرف- للمقال: <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Implementing_a_promise-based_API" rel="external nofollow">How to implement a promise-based <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a>
</p>

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

<ul>
	<li>
		المقال السابق: <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%88%D8%B9%D9%88%D8%AF-promises-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2341/" rel="">استخدام الوعود Promises في جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%84%D8%A7%D8%AA%D8%B2%D8%A7%D9%85%D9%86-%D9%88%D8%A7%D9%84%D8%A7%D9%86%D8%AA%D8%B8%D8%A7%D8%B1-asyncawait-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r921/" rel="">اللاتزامن والانتظار async/await في جافاسكربت</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-%D8%BA%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%D8%A9-r2337/" rel="">مدخل إلى جافا سكريبت غير المتزامنة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%BA%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%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-r1304/" rel="">البرمجة غير المتزامنة في جافاسكريبت</a>
	</li>
	<li>
		<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="">الوعود Promise في جافاسكربت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2348</guid><pubDate>Thu, 20 Jun 2024 15:09:01 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x648;&#x639;&#x648;&#x62F; Promises &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</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%88%D8%B9%D9%88%D8%AF-promises-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2341/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_06/----.png.3e02719efc4343e05781cbaf27e953e0.png" /></p>
<p>
	تُعد فكرة الوعود Promises أساسًا للغة جافا سكريبت غير المتزامنة. والوعد هو كائن يُعاد من الدالة غير المتزامنة ويمثّل الوضع الراهن للعملية. ولا تكون العملية قد انتهت بعد في الوقت الذي تعيد في الدالة الوعد إلى مستدعيها، لكن كائن الوعد المُعَاد يمتلك توابع لمعالجة التنفيذ الناجح أو المخفق للعملية.
</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%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D8%BA%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%D8%A9-r2337/" rel="">المقال السابق</a> عن استخدام الاستدعاءات لإنجاز الدوال غير المتزامنة. إذ نستدعي وفق هذا اﻷسلوب الدالة غير المتزامنة ممررين إليها دالة استدعاء أخرى تسمى دالة رد النداء callback، عندها تُعيد هذه الدالة قيمتها مباشرة، ثم تستدعي بعد ذلك دالة رد النداء التي مررناها عندما تنتهي العملية.
</p>

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

<h2 id="fetch">
	استخدام الواجهة البرمجية <code>fetch</code>
</h2>

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

<ol>
	<li>
		انتقل إلى الموقع: <a href="https://example.org" ipsnoembed="true" rel="external nofollow" target="_blank">https://example.org</a>
	</li>
	<li>
		افتح طرفية جافا سكريبت الموجودة ضمن <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> في نفس النافذة الفرعية.
	</li>
	<li>
		عندما نعرض مثالًا ما، انسخه إلى الطرفية، وعليك حينها إعادة تحميل الصفحة في كل مرة تُلصق فيها مثالًا جديدًا، وإلا تعترض الطرفية لأنك أعدت تصريح المتغير <code>fetchPromise</code>.
	</li>
</ol>

<p>
	سننزل في هذا المثال <a href="https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json," rel="external nofollow" target="_blank">ملف JSON</a> ونسجّل بعض المعلومات المتعلقة به، ولتنفيذ اﻷمر نرسل طلب HTTP إلى الخادم يتضمن رسالة مرسلة إليه وننتظر الاستجابة. ففي مثالنا سنطلب ملف JSON من الخادم. وكما أشرنا في <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-%D8%BA%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%D8%A9-r2337/" rel="">المقال السابق</a>، نستخدم الواجهة البرمجية <code>XMLHttpRequest</code> لتنفيذ طلبات HTTP، لكننا سنستخدم في هذا المقال الواجهة البرمجية <code>()fetch</code> وهي بديل أحدث عن كائن <code>XMLHttpRequest</code> ومبنية على الوعود.
</p>

<p>
	انسخ اﻵن الشيفرة التالية إلى طرفية جافا سكريبت في متصفحك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_8" style=""><span class="kwd">const</span><span class="pln"> fetchPromise </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</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">fetchPromise</span><span class="pun">);</span><span class="pln">

fetchPromise</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">
 console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="typ">Received</span><span class="pln"> response</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">status</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 request…"</span><span class="pun">);</span></pre>

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

<ol>
	<li>
		استدعينا الواجهة<code>()fetch</code>وأسندنا القيمة التي تعيدها إلى المتغير <code>fetchPromise</code>.
	</li>
	<li>
		سجلنا بعد ذلك مباشرة قيمة المتغير، ومن المفترض أن تشبه النتيجة ما يلي: <code>Promise { &lt;state&gt;: "pending" }</code>، لتخبرنا أنه لدينا كائن وعد <code>Promise</code> له حالة قيمتها <code>"pending"</code> ويعني ذلك أن عملية إحضار الملف لا تزال قيد التنفيذ.
	</li>
	<li>
		مررنا دالة معالجة إلى التابع <code>()then</code> العائد لكائن الوعد، فإن نجحت العملية وعندما تنتهي، يستدعي الوعد دالة المعالجة التي نمرر إليها كائن الاستجابة <code>Response</code> الذي يضم استجابة الخادم.
	</li>
	<li>
		طبعنا الرسالة "…Started request" لتدل على أننا بدأنا تنفيذ الطلب.
	</li>
</ol>

<p>
	من المفترض أن يكون خرج الشيفرة السابقة كالتالي:
</p>

<pre class="ipsCode">Promise { &lt;state&gt;: "pending" }
Started request…
Received response: 200
</pre>

<p>
	لاحظ كيف ظهرت العبارة "Started request" على الشاشة قبل تلقي الاستجابة. فعلى خلاف الدوال المتزامنة، تعيد<code>()fetch</code> قيمتها قبل أن يكتمل الطلب، مما يسمح للبرنامج بمتابعة التنفيذ. ثم يعيد البرنامج بعد ذلك رمز الحالة <code>200</code> ويعني أن الطلب قد نُفِّذ بنجاح.
</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%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D8%BA%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%D8%A9-r2337/" rel="">المقال السابق</a> الذي استخدمنا فيه معالجات أحداث على الكائن <code>XMLHttpRequest</code>، لكننا مررنا هذه المرة دالة معالجة إلى التابع <code>()then</code> العائد لكائن الوعد الذي تعيده الدالة<code>()fetch</code>.
</p>

<h2 id="">
	سلسلة من الوعود
</h2>

<p>
	بمجرد حصولك على كائن استجابة <code>Response</code> باستخدام الواجهة<code>()fetch</code>، عليك استدعاء دالة أخرى للحصول على بيانات الاستجابة، ونريدها في هذه الحالة على هيئة بيانات JSON لهذا نستدعي التابع <code>()json</code> العائد للكائن <code>Respond</code>. وكذلك الأمر، التابع <code>()json</code> غير متزامن، هنا سنكون أمام حالة نستدعي فيها دالتين غير متزامنتين على التوالي.
</p>

<p>
	جرّب اﻵن ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_10" style=""><span class="kwd">const</span><span class="pln"> fetchPromise </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

fetchPromise</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">
 </span><span class="kwd">const</span><span class="pln"> jsonPromise </span><span class="pun">=</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">json</span><span class="pun">();</span><span class="pln">
 jsonPromise</span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">data</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="pln">data</span><span class="pun">[</span><span class="lit">0</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="pun">});</span></pre>

<p>
	أضفنا في هذا المثال أيضًا التابع <code>()then</code> إلى الوعد الذي تعيده <code>()fetch</code>. لكن المعالج سيستدعي هذه المرة<code>()response.json</code> ومن ثم يمرر معالج <code>()then</code> جديد إلى الوعد الذي يعيده التابع <code>()response.json</code>.
</p>

<p>
	يُفترض في هذه الحالة طباعة العبارة في الطرفية (وهو اسم أول منتج في القائمة التي يضمها الملف "products.json"). لكن مقارنة مع الاستدعاءات التي شرحناها في مقال سابق، سنجد أننا نستدعي التابع <code>()then</code> ضمن تابع <code>()then</code> آخر وهذا مشابهة لفكرة استدعاء دالة استدعاء ضمن دالة استدعاء بشكل متعاقب، وكنا قد قلنا بأن هذا اﻷمر سيزيد من صعوبة قراءة الشيفرة وفهمها، وأطلقنا عليه اسم "جحيم الاستدعاء callback hell"، وما يحدث هنا أمر مشابه لكن مع الدالة <code>()then</code>!
</p>

<p>
	نعم، اﻷمر نفسه تمامًا، لكن الوعد يقدم ميزة خاصة وهي أن التابع <code>()then</code> يعيد هو أيضًا وعدًا يكتمل بنتيجة الدالة التي مُرر إليها. لهذا من اﻷفضل إعادة كتابة المثال السابق كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_12" style=""><span class="kwd">const</span><span class="pln"> fetchPromise </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

fetchPromise
 </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"> response</span><span class="pun">.</span><span class="pln">json</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">data</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="pln">data</span><span class="pun">[</span><span class="lit">0</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>()then</code> آخر ضمن معالج التابع <code>()then</code> الأول، يمكننا إعادة الوعد الذي يعيده التابع <code>()json</code> ثم نستدعي التابع <code>()then</code> الثاني على القيمة المُعادة. يُدعى هذا اﻷمر بسلسلة الوعود Promise chaining، ونستطيع من خلال هذه الميزة تفادي زيادة مستوى التداخل عندما نضطر إلى استدعاء الدوال غير المتزامنة بشكل متتالٍ.
</p>

<p>
	قبل الانتقال إلى الخطوة التالية، علينا إضافة شيء آخر، وهو التأكد من قبول الخادم للطلب وقدرته على معالجته قبل أن نحاول قراءة الاستجابة، ولتنفيذ اﻷمر نتحقق من رمز حالة الطلب ونعرض خطأ إن لم يكن رمز الحالة <code>200</code> (أو <code>OK</code>)
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_14" style=""><span class="kwd">const</span><span class="pln"> fetchPromise </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

fetchPromise
 </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">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">response</span><span class="pun">.</span><span class="pln">ok</span><span class="pun">)</span><span class="pln"> </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="pln">HTTP error</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">status</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"> response</span><span class="pun">.</span><span class="pln">json</span><span class="pun">();</span><span class="pln">
 </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">data</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="pln">data</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">name</span><span class="pun">);</span><span class="pln">
 </span><span class="pun">});</span></pre>

<h2 id="-1">
	التقاط اﻷخطاء
</h2>

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

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

<p>
	جرّب هذه النسخة التي تستخدم <code>()catch</code> وتُعدّل عنوان URL حتى تُخفق العملية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_16" style=""><span class="kwd">const</span><span class="pln"> fetchPromise </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"bad-scheme://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

fetchPromise
 </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">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">response</span><span class="pun">.</span><span class="pln">ok</span><span class="pun">)</span><span class="pln"> </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="pln">HTTP error</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">status</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"> response</span><span class="pun">.</span><span class="pln">json</span><span class="pun">();</span><span class="pln">
 </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">data</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="pln">data</span><span class="pun">[</span><span class="lit">0</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="pun">.</span><span class="kwd">catch</span><span class="pun">((</span><span class="pln">error</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">error</span><span class="pun">(`</span><span class="typ">Could</span><span class="pln"> not </span><span class="kwd">get</span><span class="pln"> products</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">error</span><span class="pun">}`);</span><span class="pln">
 </span><span class="pun">});</span></pre>

<p>
	نفّذ الشيفرة السابقة، ومن المفترض أن ترى الخطأ الذي يعرضه التابع <code>()catch</code>.
</p>

<h2 id="-2">
	المصطلحات الخاصة بالوعود
</h2>

<p>
	تستخدم الوعود مجموعة مخصصة من المصطلحات التي لا بد من توضيحها.
</p>

<p>
	بداية للوعد حالة من ثلاث حالات وهي كالتالي:
</p>

<ul>
	<li>
		<strong>قيد التنفيذ pending</strong>: يُنشأ كائن الوعد في هذه الحالة، لكن الدالة غير المتزامنة المرتبطة به لم تنجح أو تخفق بعد. وتوافق هذه الحالة إعادة الوعد إلى الدالة بعد استدعاء<code>()fetch</code> بينما لا يزال الطلب قيد التنفيذ.
	</li>
	<li>
		<strong>منجز fulfilled</strong>: وهي حالة نجاح العملية غير المتزامنة، ويُستدعى حينها التابع <code>()then</code>.
	</li>
	<li>
		<strong>مرفوض rejected</strong>: وهي حالة إخفاق العملية غير المتزامنة، ويُستدعى عندها التابع <code>()catch</code>.
	</li>
</ul>

<p>
	أما معنى "النجاح" أو "اﻹخفاق" فيعود للواجهة البرمجية المستخدمة. فالواجهة<code>()fetch</code> مثلًا ترفض الوعد المعاد لأسباب منها خطأ في الشبكة يمنع إرسال الطلب، وتنجزه عندما يعيد الخادم الاستجابة حتى لو كانت اﻹستجابة حالة خطأ مثل <code>404 Not Found.</code>
</p>

<p>
	كما نستخدم أيضًا مصطلح "<strong>مسوّىً settled</strong>" ليشير إلى حالتي الرفض أو اﻹنجاز. ونقول عن الوعد أنه "<strong>مقضي resolved</strong>" إن جرت "<strong>تسويته settled</strong>" أو كان "<strong>مقفلًا locked in</strong>" بانتظار حالة وعد آخر.
</p>

<h2 id="-3">
	الجمع بين عدة وعود
</h2>

<p>
	إن تكوّنت العملية غير المتزامنة من عدة دوال نستخدم حينها سلسلة من الوعود، ولا بد حينها من تسوية كل وعد قبل الانتقال إلى اﻵخر. لكنك قد تحتاج أحيانًا إلى الجمع بين عدة استدعاءات لدوال غير المتزامنة، لهذا تزوّدك الواجهة البرمجية <code>()Promis</code> ببعض الدوال المساعدة.
</p>

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

<ul>
	<li>
		منجزَا: عندما تُنجز كل الوعود في المصفوفة. ويُستدعى عند ذلك معالج التابع <code>()then</code> وتُمرّر له مصفوفة من الاستجابات وبنفس ترتيب الوعود التي مُررت إلى التابع <code>()all.</code>
	</li>
	<li>
		مرفوضًا: إن رٌفض أي من وعود المصفوفة، ويُستدعى عند ذلك معالج التابع <code>()catch</code> ويُمرر له الخطأ الناتج عن الوعد الذي رُفض.
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_18" style=""><span class="kwd">const</span><span class="pln"> fetchPromise1 </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</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"> fetchPromise2 </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found"</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"> fetchPromise3 </span><span class="pun">=</span><span class="pln"> fetch</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="pun">);</span><span class="pln">

</span><span class="typ">Promise</span><span class="pun">.</span><span class="pln">all</span><span class="pun">([</span><span class="pln">fetchPromise1</span><span class="pun">,</span><span class="pln"> fetchPromise2</span><span class="pun">,</span><span class="pln"> fetchPromise3</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">responses</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">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> response </span><span class="kwd">of</span><span class="pln"> responses</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">$</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">url</span><span class="pun">}:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">status</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="kwd">catch</span><span class="pun">((</span><span class="pln">error</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">error</span><span class="pun">(`</span><span class="typ">Failed</span><span class="pln"> to fetch</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">error</span><span class="pun">}`);</span><span class="pln">
 </span><span class="pun">});</span></pre>

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

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

<pre class="ipsCode">https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json: 200
https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found: 404
https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json: 200
</pre>

<p>
	جرّب أن تنفّذ الشيفرة السابقة بعد كتابة العناوين بشكل خاطئ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_20" style=""><span class="kwd">const</span><span class="pln"> fetchPromise1 </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</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"> fetchPromise2 </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found"</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"> fetchPromise3 </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"bad-scheme://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

</span><span class="typ">Promise</span><span class="pun">.</span><span class="pln">all</span><span class="pun">([</span><span class="pln">fetchPromise1</span><span class="pun">,</span><span class="pln"> fetchPromise2</span><span class="pun">,</span><span class="pln"> fetchPromise3</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">responses</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">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> response </span><span class="kwd">of</span><span class="pln"> responses</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">$</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">url</span><span class="pun">}:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">status</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="kwd">catch</span><span class="pun">((</span><span class="pln">error</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">error</span><span class="pun">(`</span><span class="typ">Failed</span><span class="pln"> to fetch</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">error</span><span class="pun">}`);</span><span class="pln">
 </span><span class="pun">});</span></pre>

<p>
	نتوقع اﻵن أن تُنفَّذ دالة المعالجة الخاصة بالتابع <code>()catch</code>، ومن المفترض حينها أن يكون الخرج مشابهًا للتالي:
</p>

<pre class="ipsCode">Failed to fetch: TypeError: Failed to fetch
</pre>

<p>
	وقد تريد في بعض الحالات أن يُنجز أحد الوعود ولا يهم أيها، عندها يمكنك الاستفادة من التابع <code>()Promise.any</code> الذي يشابه <code>()Promise.all</code> لكنه يُنجز بمجرد إنجاز أي وعد في مصفوفة الوعود، ويُرفض إن رُفضت جميع الوعود:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_22" style=""><span class="kwd">const</span><span class="pln"> fetchPromise1 </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</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"> fetchPromise2 </span><span class="pun">=</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
 </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found"</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"> fetchPromise3 </span><span class="pun">=</span><span class="pln"> fetch</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="pun">);</span><span class="pln">

</span><span class="typ">Promise</span><span class="pun">.</span><span class="pln">any</span><span class="pun">([</span><span class="pln">fetchPromise1</span><span class="pun">,</span><span class="pln"> fetchPromise2</span><span class="pun">,</span><span class="pln"> fetchPromise3</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">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">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">url</span><span class="pun">}:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">status</span><span class="pun">}`);</span><span class="pln">
 </span><span class="pun">})</span><span class="pln">
 </span><span class="pun">.</span><span class="kwd">catch</span><span class="pun">((</span><span class="pln">error</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">error</span><span class="pun">(`</span><span class="typ">Failed</span><span class="pln"> to fetch</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">error</span><span class="pun">}`);</span><span class="pln">
 </span><span class="pun">});</span></pre>

<p>
	<strong>ملاحظة</strong>: لا يُمكن في هذه الحالة توقّع أي وعد سيُنجز أولًا.
</p>

<p>
	للتعرف على بقية التوابع التي يمكن استخدامها للجمع بين الوعود راجع <a href="https://wiki.hsoub.com/JavaScript/Promise/Using_promises" rel="external" target="_blank">توثيق <code>()Promis</code></a>.
</p>
<iframe allowfullscreen="" class="ipsEmbed_finishedLoading" data-controller="core.front.core.autosizeiframe" data-embedauthorid="3889" data-embedcontent="" data-embedid="embed9201515357" 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: 469px; max-width: 500px;margin:auto"></iframe>

<h2 id="asyncawait">
	استخدام التعليمتين <code>async</code> و <code>await</code>
</h2>

<p>
	تُسهّل التعليمة <code>async</code> عمل الشيفرة غير المتزامنة التي تعتمد على الوعود، فإضافة هذه التعليمة إلى بداية الدالة يجعلها دالة غير متزامنة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_24" style=""><span class="kwd">async</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> myFunction</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 </span><span class="com">// This is an async function</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	وهكذا ستتمكن من كتابة شيفرة غير متزامنة مع أنها تبدو كذلك. لهذا سنحاول كتابة مثال<code>()fetch</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_26" style=""><span class="kwd">async</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> fetchProducts</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">//`()fetch` تنتظر الدالة بعد هذا السطر حتى يسوّى الاستدعاء</span><span class="pln">
    </span><span class="com">// الذي سيُعسد استجابة أو يرمي خطأ</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
     </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</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">response</span><span class="pun">.</span><span class="pln">ok</span><span class="pun">)</span><span class="pln"> </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="pln">HTTP error</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">status</span><span class="pun">}`);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="com">//`response.json()` تنتظر الدالة بعد هذا السطر حتى يسوّى الاستدعاء</span><span class="pln">
    </span><span class="com">//أو يرمي خطأ JSON الذي يعيد كائن</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">json</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="lit">0</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">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">error</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">error</span><span class="pun">(`</span><span class="typ">Could</span><span class="pln"> not </span><span class="kwd">get</span><span class="pln"> products</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">error</span><span class="pun">}`);</span><span class="pln">
 </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fetchProducts</span><span class="pun">();</span></pre>

<p>
	نستدعي هنا الدالة <code>()await fetch</code> وسنحصل على كائن استجابة <code>Response</code> مكتمل بدلًا من الوعد <code>()Promis</code>وكأن<code>()fetch</code>دالة متزامنة.
</p>

<p>
	ونستطيع أيضًا استخدام الكتلة <code>try...catch</code> لمعالجة اﻷخطاء كما لو كنا نكتب شيفرة متزامنة. وتذكر أن الدوال غير المتزامنة تُعيد وعدًا دائمًا، لهذا لا يمكن أن نكتب شيفرة كهذه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7376_10" style=""><span class="kwd">async</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> fetchProducts</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
     </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</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">response</span><span class="pun">.</span><span class="pln">ok</span><span class="pun">)</span><span class="pln"> </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="pln">HTTP error</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">status</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"> data </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</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="kwd">return</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">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">error</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">error</span><span class="pun">(`</span><span class="typ">Could</span><span class="pln"> not </span><span class="kwd">get</span><span class="pln"> products</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">error</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">const</span><span class="pln"> promise </span><span class="pun">=</span><span class="pln"> fetchProducts</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">promise</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">//هو كائن وعد فلن تعمل هذه الشيفرة "promise"</span></pre>

<p>
	ويجب عليك تصحيح الكود السابق على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_28" style=""><span class="kwd">async</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> fetchProducts</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
     </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</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">response</span><span class="pun">.</span><span class="pln">ok</span><span class="pun">)</span><span class="pln"> </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="pln">HTTP error</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">status</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"> data </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</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="kwd">return</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">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">error</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">error</span><span class="pun">(`</span><span class="typ">Could</span><span class="pln"> not </span><span class="kwd">get</span><span class="pln"> products</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">error</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">const</span><span class="pln"> promise </span><span class="pun">=</span><span class="pln"> fetchProducts</span><span class="pun">();</span><span class="pln">
promise</span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</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="lit">0</span><span class="pun">].</span><span class="pln">name</span><span class="pun">));</span></pre>

<p>
	وتذكر أن استخدام <code>await</code> يكون ضمن دالة، إلا في الحالة التي تكون فيها الشيفرة ضمن وحدة JavaScript module وليس ضمن سكريبت نمطي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3316_30" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 </span><span class="com">// using await outside an async function is only allowed in a module</span><span class="pln">
 </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">
    </span><span class="str">"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"</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">response</span><span class="pun">.</span><span class="pln">ok</span><span class="pun">)</span><span class="pln"> </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="pln">HTTP error</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">response</span><span class="pun">.</span><span class="pln">status</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"> data </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">json</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="lit">0</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">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">error</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">error</span><span class="pun">(`</span><span class="typ">Could</span><span class="pln"> not </span><span class="kwd">get</span><span class="pln"> products</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">error</span><span class="pun">}`);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	قد تستخدم دوال <code>async</code> كثيرًا مقارنة باستخدام سلسلة الوعود لكونها تجعل العمل مع الوعود أكثر وضوحًا. وتذكر أن <code>await</code> -كما هو حال سلسلة الوعود- تجبر العمليات المتزامنة على التنفيذ المتسلسل، وهذا أمر ضروري إن اعتمدت نتيجة العملية الثانية على سابقتها، أما إن لم يكن الوضع كذلك، ففكرّ في هذه الحالة باستخدام  الدالة <code>()Promise.all</code>.
</p>

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

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

<p>
	وتسّهل التعليمتان <code>async</code> و <code>await</code> بناء عمليات باستدعاء سلسلة من الدوال غير المتزامنة المتتابعة دون الحاجة إلى سلاسل صريحة من الوعود وكتابة شيفرة شبيهة بالشيفرة المتزامنة.
</p>

<p>
	تعمل الوعود في النسخ اﻷخيرة من معظم المتصفحات الحديثة، وستكون المشكلة فقط مع متصفحي أوبرا ميني Opera mini وإنترنت إكسبلورر 11 والنسخ اﻷقدم.
</p>

<p>
	لم نناقش بالتأكيد كل ميزات الوعود في مقالنا الحالي، بل سلطنا الضوء على الميزات اﻷكثر أهمية واستخدامًا، وستتعلم خلال مسيرتك في تعلم جافا سكريبت الكثير من الميزات والتقنيات المفيدة الأخرى، ويجدر بالذكر أن الكثير من واجهات الويب البرمجية مبنية أساسًا على الوعود مثل <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API" rel="external nofollow" target="_blank">WebRTC</a> و <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API" rel="external nofollow" target="_blank">Web Audio <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> <a href="https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API" rel="external nofollow" target="_blank">Media Capture and Streams <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> وغيرها الكثير.
</p>

<p>
	ترجمة -وبتصرف- للمقال: <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Promises" rel="external nofollow" target="_blank">How to use promises</a>
</p>

<p>
	اقرأ أيضًا:
</p>

<ul>
	<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-%D8%BA%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%D8%A9-r2337/" rel="">مدخل إلى جافا سكريبت غير المتزامنة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%84%D8%A7%D8%AA%D8%B2%D8%A7%D9%85%D9%86-%D9%88%D8%A7%D9%84%D8%A7%D9%86%D8%AA%D8%B8%D8%A7%D8%B1-asyncawait-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r921/" rel="">اللاتزامن والانتظار async/await في جافاسكربت</a>
	</li>
	<li>
		<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="">الوعود Promise في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%BA%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%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-r1304/" rel="">البرمجة غير المتزامنة في جافاسكريبت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2341</guid><pubDate>Mon, 10 Jun 2024 15:08:02 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A; &#x63A;&#x64A;&#x631; &#x627;&#x644;&#x645;&#x62A;&#x632;&#x627;&#x645;&#x646;&#x629;</title><link>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-%D8%BA%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%D8%A9-r2337/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_06/-----.png.d850a12adfcb26131973c811e0c32d70.png" /></p>
<p>
	نتحدث في هذا المقال عن مفهومي البرمجة المتزامنة synchronous وغير المتزامنة asynchronous، وفوائد استخدام التقنيات غير المتزامنة، كما نتحدث بإيجاز عن المشاكل التي تعلّقت تاريخيًا بتنفيذ الدوال غير المتزامنة في جافا سكريبت.
</p>

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

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

<ul>
	<li>
		<code>()fetch</code>: تستخدم لإحضار الموارد باستخدام <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-http-%D8%B4%D8%B1%D8%AD-%D8%A7%D9%84%D8%AA%D8%AE%D8%A7%D8%B7%D8%A8-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-%D9%88%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-r74/" rel="">طلبات HTTP</a>.
	</li>
	<li>
		<code>()getUserMedia</code>: تستخدم للوصول إلى كاميرا أو ميكروفون المستخدم.
	</li>
	<li>
		<code>()showOpenFilePicke</code>: تستخدم لتطلب من المستخدم اختيار ملف.
	</li>
</ul>

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

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

<h2 id="-1">
	البرمجة المتزامنة
</h2>

<p>
	لنتأمل الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4826_7" style=""><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Muhammd"</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="pun">,</span><span class="pln"> my name is $</span><span class="pun">{</span><span class="pln">name</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">greeting</span><span class="pun">);</span><span class="pln">
</span><span class="com">// "Hello, my name is Muhammd!"</span></pre>

<p>
	في هذه الشيفرة:
</p>

<ol>
	<li>
		<code>name</code>: يصرّح عن نص.
	</li>
	<li>
		<code>greeting</code>: يصرّح عن نص آخر يستخدم المتغير <code>name</code>.
	</li>
	<li>
		تطبع الشيفرة بعد ذلك رسالة الترحيب على الطرفية.
	</li>
</ol>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4826_9" style=""><span class="kwd">function</span><span class="pln"> makeGreeting</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">return</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> my name is $</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">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Muhammd"</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"> makeGreeting</span><span class="pun">(</span><span class="pln">name</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">greeting</span><span class="pun">);</span><span class="pln">
</span><span class="com">// "Hello, my name is Muhammd!"</span></pre>

<p>
	فالدالة <code>()makeGreating</code> هي دالة متزامنة، لأن مُستدعيها سينتظر حتى تنهي الدالة عملها وتعيد القيمة المطلوبة ثم يستأنف تنفيذ الشيفرة البرمجية.
</p>

<h3 id="-2">
	دالة متزامنة تستغرق وقتًا في التنفيذ
</h3>

<p>
	ماذا لو استغرقت الدالة المتزامنة وقتًا طويلًا في التنفيذ؟
</p>

<p>
	سنعرض تاليًا برنامجًا يعتمد على <a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA/" rel="">خوارزمية</a> ضعيفة وغير مجدية لتوليد أعداد أولية عندما ينقر المستخدم على زر "توليد أعداد أولية Generating Primes". وكلما كبر عدد اﻷعداد الأولية الذي يحدده المستخدم ستستغرق الدالة وقتًا أكبر ﻹيجاد النتيجة.
</p>

<p>
	إليك شيفرة HTML:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4826_11" style=""><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"quota"</span><span class="tag">&gt;</span><span class="pln">Number of primes:</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">"quota"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"quota"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"1000000"</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">id</span><span class="pun">=</span><span class="atv">"generate"</span><span class="tag">&gt;</span><span class="pln">Generate primes</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">id</span><span class="pun">=</span><span class="atv">"reload"</span><span class="tag">&gt;</span><span class="pln">Reload</span><span class="tag">&lt;/button&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">"output"</span><span class="tag">&gt;&lt;/div&gt;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4826_13" style=""><span class="kwd">const</span><span class="pln"> MAX_PRIME </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1000000</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> isPrime</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">
 </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">2</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;=</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">n</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">n </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"> </span><span class="pun">{</span><span class="pln">
     </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</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"> n </span><span class="pun">&gt;</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">const</span><span class="pln"> random </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"> </span><span class="pun">=&gt;</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"> max</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> generatePrimes</span><span class="pun">(</span><span class="pln">quota</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"> primes </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">primes</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&lt;</span><span class="pln"> quota</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"> candidate </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">(</span><span class="pln">MAX_PRIME</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">isPrime</span><span class="pun">(</span><span class="pln">candidate</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
     primes</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">candidate</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"> primes</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"> quota </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">"#quota"</span><span class="pun">);</span><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><span class="pln">

document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"#generate"</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"> primes </span><span class="pun">=</span><span class="pln"> generatePrimes</span><span class="pun">(</span><span class="pln">quota</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
 output</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">Finished</span><span class="pln"> generating $</span><span class="pun">{</span><span class="pln">quota</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}</span><span class="pln"> primes</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">querySelector</span><span class="pun">(</span><span class="str">"#reload"</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">
 document</span><span class="pun">.</span><span class="pln">location</span><span class="pun">.</span><span class="pln">reload</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="200" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/eYavmNX?default-tab=result" style="width: 100%;" title="frame_a_long-running_synchronous_function">See the Pen frame_a_long-running_synchronous_function by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<p>
	جرّب أن تنقر على الزر "Generate primes"، ستلاحظ أن الحاسوب سيتأخر عدة ثوان (وفقًا لسرعة حاسوبك) قبل أن يعرض رسالة الانتهاء "!Finished".
</p>

<h3 id="-3">
	مشاكل الدوال المتزامنة
</h3>

<p>
	تشبه شيفرة المثال التالي ما تنفذه شيفرة المثال السابق باستثناء وجود مربع نص لتكتب فيه. جرّب أن تنقر اﻵن على الزر "Generate primes" ثم حاول أن تكتب مباشرةً شيئًا ما في مربع النص. ما ستلاحظه أن البرنامج سيفقد تجاوبه طالما أن الدالة <code>()generatePrimes</code> قيد التنفيذ ولن تتمكن من الكتابة في مربع النص أو أن تنقر في أي مكان أو تفعل أي شيء.
</p>

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

<p>
	يعود السبب في ذلك إلى أن برنامج جافا سكريبت ذو <a href="https://academy.hsoub.com/programming/java/%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-%D8%A7%D9%84%D8%AE%D9%8A%D9%88%D8%B7-threads-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1484/" rel="">خيط معالجة</a> وحيد single-threaded. وخيط المعالجة هو سلسلة من التعليمات يتبعها البرنامج. ولأن البرنامج وحيد الخيط، سينفذ التعليمات واحدة تلو اﻷخرى. لهذا استغرقت الدالة المتزامنة السابقة وقتًا حتى تعيد قيمتها وكان علينا الانتظار حتى تنتهي.
</p>

<p>
	وما نحتاجه عادة في برنامجنا طريقة لتنفيذ اﻵتي:
</p>

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

<p>
	هذه النقاط ما تقدمه بالفعل الدوال غير المتزامنة، وسنتابع في هذا المقال شرح كيفية إنجاز هذه الدوال في جافا سكريبت.
</p>

<h2 id="eventhandlers">
	معالجات اﻷحداث Event Handlers
</h2>

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

<p>
	وقد استخدمت بعض الواجهات البرمجية غير المتزامنة في البدايات هذا اﻷسلوب، نذكر منها الواجهة البرمجية <code>XMLHttpRequest</code> التي تمكنك من إرسال طلبات HTTP إلى خادم واستقبالها باستخدام جافا سكريبت. فهذه العمليات قد تستغرق وقتًا، لهذا فهي غير المتزامنة. وتتلقى من خلال هذه الواجهة تنبيهًا عن تقدم الطلب وانتهائه عن طريق ربط مترصد أحداث Event Listener إلى الكائن <code>XMLHttpRequest</code>.
</p>

<p>
	نعرض في المثال التالي طريقة تنفيذ اﻷمر، فعندما تنقر على الزر "انقر ﻹرسال طلب Click to start request"، سننشئ كائن <code>XMLHttpRequest</code> جديد، ثم نترصد وقوع الحدث <code>loadend</code> (انتهاء التحميل). يطبع بعد ذلك معالج الحدث الرسالة "!Finished" إضافة إلى رمز الحالة Status Code.
</p>

<p>
	بعد إضاف معالج <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>، نرسل الطلب. ولاحظ أنه بعد إرسال الطلب يمكننا طباعة العبارة "Started XHR request" أي يتابع برنامجنا تنفيذ تعليماته في الفترة التي يُعالج فيها الطلب، ثم يُستدعى معالج الحدث عند اكتمال الطلب.
</p>

<p>
	إليك شيفرة HTML:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4826_15" style=""><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"xhr"</span><span class="tag">&gt;</span><span class="pln">Click to start request</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">id</span><span class="pun">=</span><span class="atv">"reload"</span><span class="tag">&gt;</span><span class="pln">Reload</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;pre</span><span class="pln"> </span><span class="atn">readonly</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"event-log"</span><span class="tag">&gt;&lt;/pre&gt;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4826_17" style=""><span class="kwd">const</span><span class="pln"> log </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">".event-log"</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">"#xhr"</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">
 log</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">const</span><span class="pln"> xhr </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">

 xhr</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"loadend"</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">
    log</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">log</span><span class="pun">.</span><span class="pln">textContent</span><span class="pun">}</span><span class="typ">Finished</span><span class="pln"> </span><span class="kwd">with</span><span class="pln"> status</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">xhr</span><span class="pun">.</span><span class="pln">status</span><span class="pun">}`;</span><span class="pln">
 </span><span class="pun">});</span><span class="pln">

 xhr</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="pln">
    </span><span class="str">"GET"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"https://raw.githubusercontent.com/mdn/content/main/files/en-us/_wikihistory.json"</span><span class="pun">,</span><span class="pln">
 </span><span class="pun">);</span><span class="pln">
 xhr</span><span class="pun">.</span><span class="pln">send</span><span class="pun">();</span><span class="pln">
 log</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">log</span><span class="pun">.</span><span class="pln">textContent</span><span class="pun">}</span><span class="typ">Started</span><span class="pln"> XHR request\n</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">querySelector</span><span class="pun">(</span><span class="str">"#reload"</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">
 log</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">
 document</span><span class="pun">.</span><span class="pln">location</span><span class="pun">.</span><span class="pln">reload</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="200" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/gOJmbMx?default-tab=result" style="width: 100%;" title="frame_event_handlers">See the Pen frame_event_handlers by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</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%A7%EF%BB%B7%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%D9%8A%D8%A8%D8%AA-r2306/" rel="">مدخل إلى اﻷحداث في جافا سكريبت</a>، لكن بدل أن يكون الحدث الذي نترصده هو فعل ينفّذه المستخدم مثل النقر على زر، سيكون الحدث تغيّر حالة كائن ما.
</p>

<h2 id="-4">
	دوال رد النداء Callbacks
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4826_19" style=""><span class="kwd">function</span><span class="pln"> doStep1</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="kwd">return</span><span class="pln"> init </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">function</span><span class="pln"> doStep2</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="kwd">return</span><span class="pln"> init </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</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"> doStep3</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="kwd">return</span><span class="pln"> init </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">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> doOperation</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"> result </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
 result </span><span class="pun">=</span><span class="pln"> doStep1</span><span class="pun">(</span><span class="pln">result</span><span class="pun">);</span><span class="pln">
 result </span><span class="pun">=</span><span class="pln"> doStep2</span><span class="pun">(</span><span class="pln">result</span><span class="pun">);</span><span class="pln">
 result </span><span class="pun">=</span><span class="pln"> doStep3</span><span class="pun">(</span><span class="pln">result</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">result</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">result</span><span class="pun">}`);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

doOperation</span><span class="pun">();</span></pre>

<p>
	لدينا هنا عملية واحدة مقسّمة إلى ثلاث خطوات تتعلق كل واحدة بسابقتها. إذ تضيف الخطوة الأولى 1 إلى الدخل وتضيف الثانية العدد 2 والثالثة تُضيف العدد 3. فلو كان الدخل هو 0 ستكون النتيجة 6 (0+1+2+3). إن هذا البرنامج سهل ومباشر وفق أسلوب البرمجة المتزامنة، لكن إن نفذناه وفق أسلوب دوال رد النداء، سنجد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4826_21" style=""><span class="kwd">function</span><span class="pln"> doStep1</span><span class="pun">(</span><span class="pln">init</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">
 </span><span class="kwd">const</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> init </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
 callback</span><span class="pun">(</span><span class="pln">result</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"> doStep2</span><span class="pun">(</span><span class="pln">init</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">
 </span><span class="kwd">const</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> init </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
 callback</span><span class="pun">(</span><span class="pln">result</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"> doStep3</span><span class="pun">(</span><span class="pln">init</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">
 </span><span class="kwd">const</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> init </span><span class="pun">+</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
 callback</span><span class="pun">(</span><span class="pln">result</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"> doOperation</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 doStep1</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">result1</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">
    doStep2</span><span class="pun">(</span><span class="pln">result1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">result2</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">
     doStep3</span><span class="pun">(</span><span class="pln">result2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">result3</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="pln">result</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">result3</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">

doOperation</span><span class="pun">();</span></pre>

<p>
	ولأنه علينا استدعاء دوال رد النداء، ستكون النتيجة دالة <code>()doOperation</code> متداخلة بشدة، ومن الصعب حينها قراءتها وتنقيحها. يُعرف هذا الأمر باسم "جحيم دوال رد النداء callback hell" أو "هرم الهلاك pyramid of doom" إذ تتخذ الدوال المتداخلة شكلًا هرميًا.
</p>

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

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

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

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%83%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B1%D8%AA%D8%AF%D8%A9-%D8%A7%D9%84%D9%85%D9%84%D9%88%D9%86%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-r2324/" rel="">بناء تطبيق كرات مرتدة ملونة باستخدام الكائنات في جافا سكريبت -الجزء الثاني</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A5%D8%B1%D8%B3%D8%A7%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D8%B3%D8%AA%D9%84%D8%A7%D9%85%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1294/" rel="">إرسال البيانات واستلامها عبر الشبكة في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%BA%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%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-r1304/" rel="">البرمجة غير المتزامنة في جافاسكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/nodejs/%D8%B7%D8%B1%D9%82-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%B4%D9%8A%D9%81%D8%B1%D8%A7%D8%AA-%D8%BA%D9%8A%D8%B1-%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%D8%A9-%D8%A7%D9%84%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D9%81%D9%8A-nodejs-r1743/" rel="">طرق كتابة شيفرات غير متزامنة التنفيذ في Node.js</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2337</guid><pubDate>Sun, 02 Jun 2024 15:00:00 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x627;&#x644;&#x643;&#x631;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x631;&#x62A;&#x62F;&#x629; &#x627;&#x644;&#x645;&#x644;&#x648;&#x646;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x643;&#x627;&#x626;&#x646;&#x627;&#x62A; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A; -&#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x62B;&#x627;&#x646;&#x64A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%83%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B1%D8%AA%D8%AF%D8%A9-%D8%A7%D9%84%D9%85%D9%84%D9%88%D9%86%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-r2324/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_05/-.png.dfc316fc6910bd654a04ee533f23aa63.png" /></p>
<p>
	يُطلب منك في هذا التمرين التطبيقي أن تستخدم تطبيق الكرات المرتدة الذي بنيناه في <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%83%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B1%D8%AA%D8%AF%D8%A9-%D8%A7%D9%84%D9%85%D9%84%D9%88%D9%86%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r2323/" rel="">المقال السابق</a> كنقطة انطلاق ومن ثم إضافة بعض الميزات المهمة اﻷخرى.
</p>

<p>
	كما ننصحك قبل محاول العمل على هذا التمرين الاطلاع على سلسلة المقالات السابقة التي تشرح <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%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-%D9%88%D8%AA%D8%AD%D9%82%D9%8A%D9%82%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2316/" rel="">مبادئ البرمجة بالكائنات</a> في جافا سكريبت.
</p>

<h2 id="-1">
	نقطة الانطلاق
</h2>

<p>
	انسخ بداية الملفات <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/bouncing-balls/index-finished.html" rel="external nofollow">index-finished.html</a> و <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/bouncing-balls/style.css" rel="external nofollow">style.css</a> و <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/bouncing-balls/main-finished.js" rel="external nofollow">main-finished.js</a> إلى حاسوبك -وهي ملفات تخص التمرين التطبيقي في المقال السابق- واحفظها في مجلد جديد. كما يمكنك استخدام محررات على اﻹنترنت مثل CodePen و JSFiddle و Glitch. إذ تسمح هذه المحررات بلصق شيفرة HTML و CSS ضمن المحرر، لكن إن لم يكن للمحرر الذي تستخدمه نافذة مخصصة شفرة جافا سكريبت، بإمكانك حينها وضع الشيفرة داخل عنصر <code>&lt;script&gt;</code> في صفحة HTML.
</p>

<h2 id="-2">
	نصائح وتلميحات
</h2>

<p>
	إليك بعض المؤشرات التي تخص التطبيق قبل أن تبدأ:
</p>

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

<h2 id="-3">
	موجز المشروعتأكل
</h2>

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

<p>
	تعرض الصورة التالية مثالًا عما سيكونه التطبيق عند إنجازه:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="149545" href="https://academy.hsoub.com/uploads/monthly_2024_05/01_bouncing-evil-circle.png.374fd025776511d69e95f73c21cac05d.png" rel=""><img alt="01 bouncing evil circle" class="ipsImage ipsImage_thumbnailed" data-fileid="149545" data-unique="0v4lls43j" src="https://academy.hsoub.com/uploads/monthly_2024_05/01_bouncing-evil-circle.png.374fd025776511d69e95f73c21cac05d.png"> </a>
</p>

<p>
	ولتكوّن فكرة أوضح، ألقِ نظرة على <a href="https://mdn.github.io/learning-area/javascript/oojs/assessment/" rel="external nofollow">التطبيق المكتمل</a> لكن لا تختلس النظر إلى شيفرته!
</p>

<h2 id="-4">
	الخطوات التي عليك إكمالها
</h2>

<p>
	تصف اﻷقسام التالية ما عليك إنجازه.
</p>

<h3 id="shape">
	إنشاء الصنف <code>shape</code>
</h3>

<p>
	أنشئ قبل كل شيء الصنف <code>Shape</code>. ويمتلك هذا الصنف دالة بانية فقط تُعرّف الخاصيات <code>x</code> و <code>y</code> و <code>velX</code> و <code>velY</code> كما تعرّفها الدالة البانية للصنف <code>()Ball</code>، لكن دون الخاصيتين <code>color</code> و <code>size</code>.
</p>

<p>
	يجب أن يرث الصنف <code>Ball</code> الكائن <code>Shape</code> باستخدام التعليمة <code>extends</code>، وينبغي للدالة البانية الخاصة بالصنف <code>Ball</code> أن:
</p>

<ul>
	<li>
		تأخذ نفس الوسطاء كما هو حالها سابقًا: <code>x</code> و <code>y</code> و <code>velX</code> و <code>velY</code> و <code>size</code> و <code>color</code>.
	</li>
	<li>
		استدعاء الدالة البانية للصنف باستخدام اﻷمر <code>()super</code>، وتمرير الوسطاء <code>x</code> و <code>y</code> و <code>velX</code> و <code>velY</code> إليها.
	</li>
	<li>
		تهيئة الخاصيتين <code>color</code> و <code>size</code> من القيم التي تُمرر إليها.
	</li>
</ul>

<p>
	وعلى الصنف <code>Ball</code> تعريف خاصية جديدة تُدعى <code>exists</code> التي تُستخدم لتتبع وضع الكرة إن كانت لا تزال في البرنامج (لم تؤكل بعد). وينبغي أن تأخذ الخاصية قيم منطقية (<code>true</code> / <code>false</code>) وتُهيأ بالقيمة <code>true</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1821_6" style=""><span class="pln">collisionDetect</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"> ball </span><span class="kwd">of</span><span class="pln"> balls</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="pln"> </span><span class="pun">===</span><span class="pln"> ball</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> ball</span><span class="pun">.</span><span class="pln">exists</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"> dx </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">-</span><span class="pln"> ball</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> dy </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">-</span><span class="pln"> ball</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> distance </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">dx </span><span class="pun">*</span><span class="pln"> dx </span><span class="pun">+</span><span class="pln"> dy </span><span class="pun">*</span><span class="pln"> dy</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">distance </span><span class="pun">&lt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">size </span><span class="pun">+</span><span class="pln"> ball</span><span class="pun">.</span><span class="pln">size</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        ball</span><span class="pun">.</span><span class="pln">color </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">color </span><span class="pun">=</span><span class="pln"> randomRGB</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>ball.exists</code> ضمن الشرط <code>if</code>. وينبغي ألا تغيّر في تعريف التابعين أي شيء ويجب أن يبقيا تمامًا كما عرّفناهما سابقًا.
</p>

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

<h3 id="-5">
	تعريف الكرة الشريرة
</h3>

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

<p>
	أنشئ إذًا تعريفًا للصنف <code>EvilCircle</code> واجعله يرث من الصنف <code>Shape</code> باستخدام <code>extends</code>.
</p>

<h4 id="evilcircle">
	الدالة البانية للصنف <code>EvilCircle</code>
</h4>

<p>
	ينبغي أن تتميز الدالة البانية بما يلي:
</p>

<ul>
	<li>
		يُمرر لها الوسيطان <code>x</code>و <code>y</code>.
	</li>
	<li>
		تُمرر الوسيطين إلى الدالة البانية للصنف اﻷب <code>()Shape</code> مع القيمتين <code>velx</code> و <code>velY</code> واللتان تُمررا كقيم ثابتة <code>20</code>، أي عليك كتابة الشيفرة كالتالي <code>super(x,v,20,20)</code>.
	</li>
	<li>
		اضبط اللون <code>color</code> على الأبيض <code>white</code> وقياس الكرة <code>size</code> على القيمة <code>10</code>.
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1821_8" style=""><span class="pln">window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"keydown"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</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">switch</span><span class="pln"> </span><span class="pun">(</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="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"a"</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">-=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velX</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">"d"</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velX</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">"w"</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">-=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velY</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">"s"</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velY</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></pre>

<p>
	تضيف الشيفرة السابقة مترصّد لحدث الضغط على مفتاح <code>keydown</code> إلى الكائن <code>window</code>، وبالتالي، عندما يُضغط مفتاح يتفقد المتصفح قيمة الخاصية <code>key</code> لكائن الحدث لمعرفة الزر الذي ضُغط.فإن كان أحد المفاتيح اﻷربعة المخصصة، تتحرك الكرة إلى اليمين أو اليسار أو اﻷعلى أو الأسفل.
</p>

<h3 id="evilcircle-1">
	تعريف توابع الكائن <code>EvilCircle</code>
</h3>

<p>
	للصنف ثلاث توابع نشرحها تاليًا.
</p>

<h4 id="draw">
	التابع <code>()draw</code>
</h4>

<p>
	وله نفس غاية التابع <code>()draw</code> في الصنف <code>Ball</code> الذي يرسم نسخة من الكائن على اللوحة. يعمل التابع في الصنف <code>EvilCircle</code> بنفس الطريقة، لهذا بإمكانك نسخ شيفرة التابع <code>()draw</code> للصنف <code>Ball</code> ومن ثم إجراء التعديلات التالية:
</p>

<ul>
	<li>
		لا نريد أن تملئ الكرة بأي لون بل إطار خارجي فقط. وتستطيع أن تفعل ذلك بتغيير التابعين <code>fillstyle</code> و <code>fill</code> إلى التابعين <code>strokeStyle</code> و <code>stroke</code> على الترتيب.
	</li>
	<li>
		اجعل الإطار الخارجي أكثر ثخانة كي تُرى الكرة الشريرة بشكل أوضح. وتستطيع إنجاز الأمر بضبط قيمة <code>lineWidth</code> (على القيمة 3 مثلًا) وذلك بعد وضع هذه التعليمة في مكان مناسب بعد الدالة <code>()beginPath</code>.
	</li>
</ul>

<h4 id="checkbounds">
	التابع <code>()checkBounds</code>
</h4>

<p>
	ينفّذ هذا التابع ما ينفّذه الجزء الأول من التابع <code>()update</code> في الصنف <code>Ball</code> وذلك بالتحقق من وصول حافة الكرة إلى حواف الشاشة ومنعها من ذلك. لهذا انسخ شيفرة هذه الدالة وأجر عليها التعديلات التالية:
</p>

<ul>
	<li>
		احذف السطرين اﻷخيرين، فلا نريد تغيير موقع الكرة الشريرة تلقائيًا في كل إطار لأننا نريد تحريكها بطريقة أخرى كما سنرى لاحقًا.
	</li>
	<li>
		إن أعاد الشرط داخل العبارة <code>()if</code> القيمة <code>true</code>، فلن نريد في هذه الحالة تحديث قيمتي الخاصيتين <code>velx</code> و <code>velY</code> بل نريد تغيير قيمتي <code>x</code> و <code>y</code> كي ترتد الكرة الشريرة قليلًا عن الشاشة. قد يفي بالغرض إضافة أو طرح (بما يناسب) قياس الكرة الشريرة.
	</li>
</ul>

<h4 id="collisiondetect">
	التابع <code>()collisionDetect</code>
</h4>

<p>
	يعمل هذا التابع بنفس الطريقة التي يعمل فيها التابع المقابل في الصنف <code>Ball</code> لهذا بإمكانك نسخ شيفرته واستخدامها كأساس للتابع الجديد. لكن بالطبع مع إجراء التغييرات التالية:
</p>

<ul>
	<li>
		لا حاجة في الشرط <code>if</code> الخارجي للتحقق من أن الكرة المختبرة هي نفسها الكرة التي وصل إليها التكرار لأنها لم تعد كرة عادية بل الكرة الشريرة. وما عليك فعله هو التأكد من أن الكرة التي نختبرها موجودة (ما هي الخاصية التي نستخدمها؟). فإن لم تكن موجودة فإن الكرة قد أُكلت مسبقًا من قبل الكرة الشريرة، فلا حاجة لاختبارها مجددًا.
	</li>
	<li>
		لا حاجة في الشرط <code>if</code> الداخلي إلى تغيير لون الكرة عند التقاط حالة تصادم، بل عليك فقط أن تجعل الكرة التي تصطدم بالكرة الشريرة غير موجودة (كيف ستفعل ذلك؟)
	</li>
</ul>

<h3 id="-6">
	إدخال الكرة الشريرة إلى البرنامج
</h3>

<p>
	بعد أن عرّفنا الكرة الشريرة، لا بد من إظهارها فعليًا في المشهد. وﻹنجاز اﻷمر، عليك إجراء بعض التعديلات على الدالة <code>()loop</code>.
</p>

<ul>
	<li>
		أنشئ بداية نسخة جديدة عن كائن الكرة الشريرة (اضبط المعاملات اللازمة). عليك فعل ذلك مرة واحدة، وليس في كل تكرار للدالة <code>()loop</code>.
	</li>
	<li>
		في النقطة التي نتنقل فيها بين الكرات ونستدعي التوابع <code>()draw</code> و <code>()update</code> و <code>()collisionDetect</code> لكل كرة، استدع التوابع السابقة فقط إن كانت الكرة التي وصلنا إليها في التكرار موجودة.
	</li>
	<li>
		استدع التوابع <code>()draw</code> و <code>()checkBounds</code> و <code>()collisionDetect</code> لنسخة الكرة الشريرة في كل تكرار للحلقة.
	</li>
</ul>

<h3 id="-7">
	إنجاز شيفرة عداد النتيجة
</h3>

<p>
	اتبع الخطوات التالية:
</p>

<ol>
	<li>
		أضف <code>&lt;p&gt;</code> تحت العنصر <code>&lt;h1&gt;</code> في ملف HTML وفيها النص <code>Ball count</code>.
	</li>
	<li>
		أضف القاعدة التالية في آخر ملف CSS:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1821_10" style=""><span class="pln">p </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">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">35px</span><span class="pun">;</span><span class="pln">
  right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="pun">#</span><span class="pln">aaa</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	قم بإجراء التعديلات التالية في ملف جافا سكريبت:
</p>

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

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

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

<p>
	ترجمة -وبتصرف لمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features" rel="external nofollow">Adding features to our bouncing ball demo</a>
</p>

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%83%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B1%D8%AA%D8%AF%D8%A9-%D8%A7%D9%84%D9%85%D9%84%D9%88%D9%86%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r2323/" rel="">بناء تطبيق الكرات المرتدة الملونة باستخدام الكائنات في جافا سكريبت -الجزء الأول</a>
	</li>
	<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/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%AA%D8%B5%D8%A7%D9%85%D9%8A%D9%85%D8%8C-%D8%A7%D9%84%D8%A3%D9%84%D9%88%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%AE%D8%B7%D9%88%D8%B7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-canvas-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r239/" rel="">التعامل مع التصاميم، الألوان والخطوط باستخدام Canvas في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B1%D8%B3%D9%85-%D8%B9%D9%84%D9%89-%D9%84%D9%88%D8%AD%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1364/" rel="">الرسم على لوحة في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%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%D9%8A%D8%A8%D8%AA-r1354/" rel="">معالجة الأحداث في جافا سكريبت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2324</guid><pubDate>Fri, 24 May 2024 12:01:00 +0000</pubDate></item><item><title>&#x623;&#x634;&#x647;&#x631; 10 &#x645;&#x634;&#x643;&#x644;&#x627;&#x62A; &#x62A;&#x648;&#x627;&#x62C;&#x647; &#x645;&#x628;&#x631;&#x645;&#x62C;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A; JavaScript</title><link>https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B4%D9%87%D8%B1-10-%D9%85%D8%B4%D9%83%D9%84%D8%A7%D8%AA-%D8%AA%D9%88%D8%A7%D8%AC%D9%87-%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A-%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-javascript-r2328/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_05/-10-----JavaScript.png.6f95215f6c97c27619344c386d5c01e6.png" /></p>
<p>
	قد تبدو لغة جافا سكريبت JavaScript للوهلة الأولى سهلةً للغاية، إلا أن اللغة أكثر دقة وقوة وتعقيدًا مما قد تعتقده، إذ تؤدي العديد من التفاصيل الدقيقة في جافا سكريبت إلى عدد من المشكلات الشائعة - نناقش 10 منها في هذا المقال- حيث نركز على المشكلات التي تمنع التعليمات البرمجية من العمل على النحو المطلوب لتكون على دراية بهذه المخاطر وتتجنبها في سعيك لأن تصبح مطور جافا سكريبت محترفًا.
</p>

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

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

<h2 id="this">
	مشكلة جافا سكريبت الأولى: المراجع المغلوطة لـ <code>this</code>
</h2>

<p>
	ستجد دومًا ارتباكًا بين مطوري جافا سكريبت فيما يتعلق بـكلمة جافا سكريبت المفتاحية <a href="https://wiki.hsoub.com/JavaScript/this" rel="external"><code>this</code></a>
</p>

<p>
	مع تطوّر وزيادة تعقيد تقنيات برمجة جافاسكريبت و<a href="https://academy.hsoub.com/programming/advanced/%D8%A3%D9%86%D9%85%D8%A7%D8%B7-%D8%A7%D9%84%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A-design-patterns-r498/" rel="">أنماط التصميم Design Patterns</a>، بات هناك زيادة مقابلة في انتشار نطاقات المرجعية الذاتية<br>
	self-referencing scopes ضمن دوال رد النداء callbacks <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D9%86%D8%BA%D9%84%D9%82%D8%A7%D8%AA-closure-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r872/" rel="">والمنغلقات closures</a>، التي تعد المصدر الأساسي إلى حد ما للارتباك مع <code>this</code> الذي يسبب مشاكل جافا سكريبت.
</p>

<p>
	انظر إلى المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_6" style=""><span class="kwd">const</span><span class="pln"> </span><span class="typ">Game</span><span class="pln"> </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">clearLocalStorage </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">
        console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Clearing local storage..."</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">clearBoard </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">
        console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Clearing board..."</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="typ">Game</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">restart </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </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">clearLocalStorage</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">timer </span><span class="pun">=</span><span class="pln"> setTimeout</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">clearBoard</span><span class="pun">();</span><span class="pln">    </span><span class="com">// What is "this"?</span><span class="pln">
    </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="kwd">const</span><span class="pln"> myGame </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Game</span><span class="pun">();</span><span class="pln">
myGame</span><span class="pun">.</span><span class="pln">restart</span><span class="pun">();</span></pre>

<p>
	تظهر نتائج تنفيذ الشيفرة البرمجية أعلاه الخطأ التالي:
</p>

<pre class="ipsCode">Uncaught TypeError: this.clearBoard is not a function
</pre>

<p>
	لماذا؟ الأمر كله يتعلق بالسياق فسبب حدوث هذا الخطأ هو أنه عند استدعاء الدالة <code>setTimeout()‎</code>، فإنك في الواقع تستدعي <code>window.setTimeout()‎</code>. ونتيجة لذلك، تُعرَّف الدالة المجهولة anonymous function التي تُمرَّر إلى <code>setTimeout()‎</code> في سياق كائن <code>window</code> الذي لا يحتوي على تابع بالاسم <code>ClearBoard()‎</code>.
</p>

<p>
	الحل التقليدي لهذه المشكلة والمتوافق مع المتصفحات القديمة هو حفظ المرجع إلى <code>this</code> في متغير يمكن بعد ذلك توريثه عبر <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D9%86%D8%BA%D9%84%D9%82%D8%A7%D8%AA-closure-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r872/" rel="">دالة منغلقة closure function</a>، على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_8" style=""><span class="typ">Game</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">restart </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </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">clearLocalStorage</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">const</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="com">// Save reference to 'this', while it’s still this!</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">timer </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">clearBoard</span><span class="pun">();</span><span class="pln">    </span><span class="com">// Oh, OK, I do know who 'self' is!</span><span class="pln">
    </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></pre>

<p>
	ويمكن أن نستخدم حلًا مختلفًا في المتصفحات الأحدث وذلك يتضمن استخدام التابع <a href="https://wiki.hsoub.com/JavaScript/Function/bind" rel="external">()bind</a> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_12" style=""><span class="typ">Game</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">restart </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </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">clearLocalStorage</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">timer </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">reset</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="lit">0</span><span class="pun">);</span><span class="pln">  </span><span class="com">// Bind to 'this'</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="typ">Game</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">reset </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">clearBoard</span><span class="pun">();</span><span class="pln">    </span><span class="com">// OK, back in the context of the right 'this'!</span><span class="pln">
</span><span class="pun">};</span></pre>

<h2 id="">
	مشكلة جافا سكريبت الثانية: الاعتقاد بوجود نطاق على مستوى كتلة شيفرة
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_14" style=""><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">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="com">/* ... */</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">i</span><span class="pun">);</span><span class="pln">  </span><span class="com">// What will this output?</span></pre>

<p>
	إن كنت تظن أن استدعاء <code>console.log()‎</code> سيعطي خرجاً <code>undefined</code> أو خطأً ما، فتخمينك خاطئ. صدق أو لا تصدق، سيكون الخرج هنا هو <code>10</code>. لماذا؟
</p>

<p>
	في معظم اللغات البرمجية الأخرى، ستتسبب الشيفرة البرمجية السابقة في حدوث خطأ برمجي لأنّ دورة حياة المتغير (أو نطاقه) مقيّدةٌ ضمن كتلة <code>for</code>. أما في لغة جافا سكريبت، فالمتغير <code>i</code> يبقى داخل النطاق بعد اكتمال حلقة <code>for</code>، محتفظاً بالقيمة الأخيرة بعد الخروج من الحلقة. (يُعرف هذا التصرف باسم <a href="https://wiki.hsoub.com/JavaScript/var" rel="external">رفع المتغيرات</a>)
</p>

<p>
	إن دعم النطاقات على مستوى الكتل موجود في جافا سكريبت عبر <a href="https://wiki.hsoub.com/JavaScript/let" rel="external">كلمة <code>let</code> المفتاحية</a>. وكلمة <code>let</code> كانت مدعومةً بشكلٍ كبير من قبل المتصفحات وبيئنات تشغيل جافا سكريبت مثل <a href="https://wiki.hsoub.com/Node.js" rel="external">Node.js</a> منذ سنوات. وإن كان هذا جديداً عليك، حان الوقت لتتعلم المزيد حول  <span ipsnoautolink="true">نطاق المتغيرات scopes وكائنات <a href="https://wiki.hsoub.com/JavaScript/Function/prototype" rel="external">prototype</a> في جافا سكريبت</span>.
</p>

<h2 id="-1">
	مشكلة جافا سكريبت الثالثة: التسبب بتسريب الذاكرة
</h2>

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

<h3 id="1">
	تسريب الذاكرة - المثال1: المراجع المعلقة للكائنات المحذوفة
</h3>

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

	<p data-gramm="false">
		ملاحظة: ينطبق هذا المثال حصراً على محرّكات جافا سكريبت القديمة، أما الحديثة فتحوي على كانسات مهملات ذكية Garbage Collectors (أو اختصارًا) GCs بما يكفي لعلاج هذه المشكلة.
	</p>
</blockquote>

<p>
	لنضع بعين الاعتبار هذه الشيفرة البرمجية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_16" style=""><span class="kwd">var</span><span class="pln"> theThing </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">var</span><span class="pln"> replaceThing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </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"> priorThing </span><span class="pun">=</span><span class="pln"> theThing</span><span class="pun">;</span><span class="pln">  </span><span class="com">// Hold on to the prior thing</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> unused </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">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">// 'unused' is the only place where 'priorThing' is referenced,</span><span class="pln">
    </span><span class="com">// but 'unused' never gets invoked</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">priorThing</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">"hi"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
  theThing </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    longStr</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">(</span><span class="lit">1000000</span><span class="pun">).</span><span class="pln">join</span><span class="pun">(</span><span class="str">'*'</span><span class="pun">),</span><span class="pln">  </span><span class="com">// Create a 1MB object</span><span class="pln">
    someMethod</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</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">someMessage</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">
setInterval</span><span class="pun">(</span><span class="pln">replaceThing</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">    </span><span class="com">// Invoke 'replaceThing' once every second</span></pre>

<p>
	إن نفّذت الشيفرة البرمجية السابقة وراقبت استخدام الذاكرة، ستجد أنّ لديك تسريباً كبيراً للذاكرة - حوالي ميغابايت في الثانية الواحدة! لدرجة أن كانسات القمامة لن تكون قادرة على المساعدة. ما يعني أنّه يتم تسريب <code>longStr</code> في كلّ مرةٍ نستدعي فيها <code>replaceThing</code>. ولكن لماذا؟
</p>

<p>
	لنفحص الشيفرة بشكلٍ أدقّ:
</p>

<p>
	يتضمن كلّ كائن <code>theThing</code> على كائن <code>longStr</code> بحجم ميغابايت واحد. عندما نستدعي <code>replaceThing</code> في كلّ ثانية فإنّه يحتفظ بالمرجع الخاص بكائن <code>theThing</code> السّابق داخل <code>priorThing</code>، هل من الممكن أن تكون هذه هي المشكلة؟ ذلك من المستبعد، إذ يتم بشكل مسبق تحصيل dereference (أي عملية إلغاء المرجع) <code>priorThing</code> في كلّ مرةٍ (عندما نعدّل قيمة <code>priorThing</code> عبر السطر <code>priorThing = theThing;‎</code>).
</p>

<p>
	بالإضافة إلى أنه ذلك، فنحن نحصل على قيمة <code>priorThing</code> داخل الدالة <code>replaceThing</code> وفي تابع <code>unused</code>، ما يعني أنه لم يُستخدم.
</p>

<p>
	ما يعني أنّنا لم نجد الإجابة على سؤالنا حول تسريب الذاكرة هنا.
</p>

<p>
	نحتاج إلى فهمٍ أعمق لآلية عمل جافا سكريبت الداخلية لفهم ما يحدث. عادةً ما تُطبَّق الدوال المغلّفة عبر كلّ دالة ضمن كائن متصل بكائنٍ بنمط القاموس الذي يمثّل النطاق المعجميّ lexical scope. إن استخدمت كلٌّ من الدالتين اللتين تم تعريفهما داخل <code>replaceThing</code> تعليمة <code>priorThing</code>، سيكون من المهمّ أن تحصل كلاهما على الكائن نفسه، حتى لو تم تعيين <code>priorThing</code> مرارًا وتكرارًا بحيث تشترك كلتا الدالتين في البيئة المعجمية lexical environment (البيئة التي تحتوي على معلومات حول المتغيرات المحلية والعامة بالإضافة إلى الدوال المتاحة في نطاق البرنامج عند تعريف الدالة) ذاتها. ولكن ما إن تستخدم المتغيرات من قبل أيٍّ مغلّف، ستصل إلى البيئة المعجميّة المشتركة بين جميع المغلّفات في هذا النطاق. وهذا الفارق الدقيق هو ما يؤدي إلى <a href="https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156?gi=09e6523a7c31" rel="external nofollow">تسريب الذاكرة</a> هذا.
</p>

<h3 id="2">
	تسريب الذاكرة - المثال 2: المراجع الذاتية
</h3>

<p>
	لنرى هذا الجزء من الشيفرة البرمجيّة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_18" style=""><span class="kwd">function</span><span class="pln"> addClickHandler</span><span class="pun">(</span><span class="pln">element</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">click </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> onClick</span><span class="pun">(</span><span class="pln">e</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">"Clicked the "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> element</span><span class="pun">.</span><span class="pln">nodeName</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لتعليمة <code>onClick</code> هنا مغلّفًا يحافظ على مرجعٍ إلى <code>element</code> (عبر <code>element.nodeName</code>). وبإسناد <code>onClick</code> إلى <code>element.click</code> يُنشأ المرجع الدوار أي يصبح لدينا:
</p>

<p>
	<code>element</code> →<code>onClick</code> → <code>element</code> → <code>onClick</code> → <code>element</code>…
</p>

<p>
	ومن المثير للاهتمام أنّه حتّى إن أزلنا <code>element</code> من DOM، فسيمنع المرجع الذاتي circular reference (الذي يشير لنفسه بشكل دوري) أعلاه من أن نحصل على قيمة <code>element</code> و <code>onClick</code> ما يؤدي إلى تسريب الذاكرة.
</p>

<h3 id="-2">
	تجنّب تسريب الذاكرة: الأساسيّات
</h3>

<p>
	تعتمد إدارة ذاكرة جافا سكريبت (وبشكلٍ خاصّ <a href="https://academy.hsoub.com/programming/javascript/%D9%83%D9%86%D8%B3-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%87%D9%85%D9%84%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r797/" rel="">كنس البيانات المهملة</a><span style="display: none;"> </span>) بشكلٍ كبير على الوصول إلى الكائن.
</p>

<p>
	من المفترض أن تكون الكائنات التالية <strong>قابلة للوصول</strong> كما تعرف باسم "الجذور roots":
</p>

<ul>
	<li>
		الكائنات المشار إليها من أي مكان في <strong>مكدس الاستدعاءات call stack</strong> الحالي (أي جميع المتغيرات والمعاملات المحلية في الدوال التي تُستدعى حاليًا، وجميع المتغيرات في نطاق المغلّف).
	</li>
	<li>
		كلّ المتغيرات <strong>العامة</strong>.
	</li>
</ul>

<p>
	<strong>يُحتفظ بالكائنات في الذاكرة طالما يمكن الوصول إليها من أي من الجذور من خلال مرجع أو سلسلة من المراجع.</strong>
</p>

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

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_23" style=""><span class="com">// All of these evaluate to 'true'!</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="kwd">false</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'0'</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="kwd">null</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">undefined</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">" \t\r\n"</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</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">''</span><span class="pln"> </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">// And these do too!</span><span class="pln">
</span><span class="kwd">if</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="com">// ...</span></pre>

<p>
	على الرغم من كون العنصرين الأخيرين فارغين (مما قد يقودك إلى الاعتقاد بأنهما سيُقيَّمان إلى <code>false</code>)، فإن كلاً من {} و [] هما في الواقع كائنان، وسيُحوَّل <strong>أي</strong> كائن قسريًا إلى قيمة بوليانيّة مساوية إلى <code>true</code> في جافا سكريبت بما يتوافق مع <a href="https://262.ecma-international.org/#sec-toboolean" rel="external nofollow">معايير ECMA-262</a>.
</p>

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

<p>
	وبما أنّنا نتحدّث عن تحويل النوع القسري والمقارنة بين النوعين، من المهمّ ذكر أن مقارنة <code>NaN</code> مع <strong>أيّ شيء</strong> (حتّى <code>NaN</code>!) سيعيد <strong>دائمًا</strong> <code>false</code>، بالتالي لن تستطيع استخدام عوامل المساواة (<code>==</code>، <code>===</code>، <code>!=</code>، <code>!==</code>) لتحديد إذا ما كانت القيمة <code>NaN</code> أم لا، وعليك أن تستخدم بدلاً من ذلك الدالة العامة المبنية مسبقًا <code>()isNaN</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_25" style=""><span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="kwd">NaN</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">NaN</span><span class="pun">);</span><span class="pln">    </span><span class="com">// False</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="kwd">NaN</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">NaN</span><span class="pun">);</span><span class="pln">   </span><span class="com">// False</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">isNaN</span><span class="pun">(</span><span class="kwd">NaN</span><span class="pun">));</span><span class="pln">    </span><span class="com">// True</span></pre>

<h2 id="domhttpsacademyhsoubcomprogrammingjavascriptd985d8afd8aed984d8a5d984d989domr644">
	مشكلة جافا سكريبت الخامسة: التلاعب <span ipsnoautolink="true">بنموذج تمثيل المستند DOM</span> غير الفعّال
</h2>

<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> بشكل نسبي (كإضافة العناصر وتعديلها وإزالتها)، ولكنها لا تفعل ذلك مع التشديد على القيام بذلك بكفاءة.
</p>

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

<p>
	أحد البدائل الفعالة عند الحاجة إلى إضافة عناصر DOM متعددة هو استخدام <a href="https://wiki.hsoub.com/JavaScript/Document/createDocumentFragment" rel="external">أجزاء المستند</a> فقط، ما يؤدّي إلى <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%BA%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%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-r1304/" rel="">تحسين الكفاءة والأداء</a>.
</p>

<p>
	كمثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_29" style=""><span class="kwd">const</span><span class="pln"> div </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">"my_div"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> fragment </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createDocumentFragment</span><span class="pun">();</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> elems </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">'a'</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"> e </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> e </span><span class="pun">&lt;</span><span class="pln"> elems</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> e</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fragment</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">elems</span><span class="pun">[</span><span class="pln">e</span><span class="pun">]);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
div</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">fragment</span><span class="pun">.</span><span class="pln">cloneNode</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">));</span></pre>

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

<h2 id="for">
	مشكلة جافا سكريبت السادسة: الاستخدام الخاطئ لتعريف الدوالّ داخل حلقات <code>for</code>
</h2>

<p>
	لننظر إلى هذه الشيفرة البرمجيّة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_33" style=""><span class="kwd">var</span><span class="pln"> elements </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementsByTagName</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> n </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="com">// Assume we have 10 elements for this example</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"> n</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">
    elements</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">onclick </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">
        console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"This is element #"</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></pre>

<p>
	بناءً على الشيفرة البرمجيّة أعلاه، إن كان هناك 10 عناصر إدخال، فإن النقر على <strong>أيٍّ منها</strong> سيعرض "هذا هو العنصر #10"! لأنه عند استدعاء <code>onclick</code> لأي من العناصر، ستكون حلقة <code>for</code> المذكورة أعلاه قد اكتملت وستكون قيمة <code>i</code> تساوي 10 (<strong>لجميع العناصر</strong>).
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_35" style=""><span class="kwd">var</span><span class="pln"> elements </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementsByTagName</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> n </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="com">// Assume we have 10 elements for this example</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> makeHandler </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">num</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span><span class="com">// Outer function</span><span class="pln">
     </span><span class="kwd">return</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">// Inner function</span><span class="pln">
         console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"This is element #"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> num</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">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"> n</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">
    elements</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> makeHandler</span><span class="pun">(</span><span class="pln">i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	في هذه النسخة المنقحة ننفّذ <code>makeHandler</code> على الفور في كل مرة نمر فيها خلال الحلقة، وفي كل مرة يتم تلقي القيمة الحالية لـ <code>i+1</code> وربطها بمتغير <code>num</code> محدد النطاق تعيد الدالة الخارجية الدالة الداخلية (التي تستخدم أيضًا متغير <code>num</code> المحدد هذا) ويتم تعيين <code>onclick</code> الخاصة بالعنصر على تلك الدّالة الداخلية. وهذا يضمن أن كل نقرة تتلقى وتستخدم قيمة <code>i</code> المناسبة (عبر المتغير <code>num</code> المحدد).
</p>

<h2 id="-4">
	مشكلة جافا سكريبت السابعة: الفشل في الاستفادة بشكل صحيح من الوراثة النموذجية
</h2>

<p>
	يفشل عددٌ كبيرٌ من مطوري جافا سكريبت في فهم ميزات الوراثة النموذجيّة بشكل كامل، وبالتالي الاستفادة منها بشكل كامل.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_37" style=""><span class="typ">BaseObject</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</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">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">typeof</span><span class="pln"> name </span><span class="pun">!==</span><span class="pln"> </span><span class="str">"undefined"</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">name </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">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">name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'default'</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	يبدو ذلك واضحًا ومباشراً. إن أعطيت اسمًا، استخدمه، وإلّا فاضبط الاسم كـ "افتراضيّ default"، مثلاً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_39" style=""><span class="kwd">var</span><span class="pln"> firstObj </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">BaseObject</span><span class="pun">();</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> secondObj </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">BaseObject</span><span class="pun">(</span><span class="str">'unique'</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">firstObj</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln">  </span><span class="com">// -&gt; Results in 'default'</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">secondObj</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// -&gt; Results in 'unique'</span></pre>

<p>
	ولكن ماذا لو قمنا بهذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_41" style=""><span class="kwd">delete</span><span class="pln"> secondObj</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span></pre>

<p>
	ثمّ سنحصل على:
</p>

<pre class="ipsCode">console.log(secondObj.name); // -&gt; Results in 'undefined'
</pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_43" style=""><span class="typ">BaseObject</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</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><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="kwd">typeof</span><span class="pln"> name </span><span class="pun">!==</span><span class="pln"> </span><span class="str">"undefined"</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">name </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="pun">};</span><span class="pln">

</span><span class="typ">BaseObject</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'default'</span><span class="pun">;</span></pre>

<p>
	في هذه النسخة، ترث تعليمة <code>BaseObject</code> ملكيّة <code>name</code> من كائن <code>prototype</code>، الذي يوجد بشكلٍ افتراضيّ في تعليمة <code>default</code>، وبالتالي، إذا استدعي الباني بدون اسم، فسيعيّن الاسم افتراضيًا عبر <code>default</code>، وبالمثل إن أزيلت خاصية <code>name</code> من نسخة <code>BaseObject</code>، فستجرى عملية بحث في سلسلة النموذج الأولي واسترداد خاصية <code>name</code> من كائن <code>prototype</code> حيث تظل قيمته <code>default</code>. والآن نحصل على:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_45" style=""><span class="kwd">var</span><span class="pln"> thirdObj </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">BaseObject</span><span class="pun">(</span><span class="str">'unique'</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">thirdObj</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln">  </span><span class="com">// -&gt; Results in 'unique'</span><span class="pln">

</span><span class="kwd">delete</span><span class="pln"> thirdObj</span><span class="pun">.</span><span class="pln">name</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">thirdObj</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln">  </span><span class="com">// -&gt; Results in 'default'</span></pre>

<h2 id="instancemethods">
	مشكلة جافا سكريبت الثامنة: إنشاء مراجع خاطئة لتوابع النُّسَخ Instance Methods
</h2>

<p>
	لنعرّف كائنًا بسيطًا وننشئ نسخةً له كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_47" style=""><span class="kwd">var</span><span class="pln"> </span><span class="typ">MyObjectFactory</span><span class="pln"> </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="typ">MyObjectFactory</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">whoAmI </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">
    console</span><span class="pun">.</span><span class="pln">log</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="kwd">var</span><span class="pln"> obj </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">MyObjectFactory</span><span class="pun">();</span></pre>

<p>
	والآن لننشئ مرجعاً للتابع <code>whoAmI</code> لضمان سهولة العمل ولنتمكن من الوصول إليه فقط من خلال <code>whoAmI()‎</code> بدلاً من التابع <code>()obj.whoAmI</code> الأطول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_49" style=""><span class="kwd">var</span><span class="pln"> whoAmI </span><span class="pun">=</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">whoAmI</span><span class="pun">;</span></pre>

<p>
	وللتأكّد؛ خزّنّا مرجعًا للدالة، لنطبع القيمة لمتغيّرنا الجديد <code>whoAmI</code>:
</p>

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

<p>
	الخرج:
</p>

<pre class="ipsCode">function () {
    console.log(this);
}
</pre>

<p>
	يبدو الأمر جيدًا حتّى الآن.
</p>

<p>
	ولكن لنرى الفرق عندما نستدعي <code>()obj.whoAmI</code> بدلاً من مرجع السهولة الخاص بنا <code>()obj.whoAmI</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_53" style=""><span class="pln">obj</span><span class="pun">.</span><span class="pln">whoAmI</span><span class="pun">();</span><span class="pln">  </span><span class="com">// Outputs "MyObjectFactory {...}" (as expected)</span><span class="pln">
whoAmI</span><span class="pun">();</span><span class="pln">      </span><span class="com">// Outputs "window" (uh-oh!)</span></pre>

<p>
	ما الخطأ الذي حصل؟ استدعينا التابع <code>()obj.whoAmI</code> في مساحة الاسم <strong>العامة</strong>، لذا فإن <code>this</code> تُضَمّ إلى <code>window</code> (أو في الوضع الدّقيق إلى <code>undefined</code>)، و<strong>ليس</strong> إلى نسخة <code>obj</code> الخاصة بكائن <code>MyObjectFactory</code>! بمعنًى آخر، قيمة <code>this</code> تعتمد على سياق استدعائها.
</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> {} &lt; = (<code>params</code>) بدلاً من <code>{} (function (params</code> <code>this</code> ثابتة وهذا ليس مبنيًّا على سياق الاستدعاء مثل <code>this</code> للدوالّ الطبيعية، مما يمنحنا الحلّ البديل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_55" style=""><span class="kwd">var</span><span class="pln"> </span><span class="typ">MyFactoryWithStaticThis</span><span class="pln"> </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">whoAmI </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">// Note the arrow notation here</span><span class="pln">
        console</span><span class="pun">.</span><span class="pln">log</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="pun">}</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> objWithStaticThis </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">MyFactoryWithStaticThis</span><span class="pun">();</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> whoAmIWithStaticThis </span><span class="pun">=</span><span class="pln"> objWithStaticThis</span><span class="pun">.</span><span class="pln">whoAmI</span><span class="pun">;</span><span class="pln">

objWithStaticThis</span><span class="pun">.</span><span class="pln">whoAmI</span><span class="pun">();</span><span class="pln">  </span><span class="com">// Outputs "MyFactoryWithStaticThis" (as usual)</span><span class="pln">
whoAmIWithStaticThis</span><span class="pun">();</span><span class="pln">      </span><span class="com">// Outputs "MyFactoryWithStaticThis" (arrow notation benefit)</span></pre>

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

<h2 id="settimeoutsetinterval">
	مشكلة جافا سكريبت التاسعة: استخدام سلسلة كوسيط أول لدالة <code>setTimeout</code> أو <code>setInterval</code>
</h2>

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

<p>
	البديل لتمرير سلسلة كوسيط أول لهذه التوابع هو تمرير <strong>دالة</strong> بدلاً من ذلك. لنلقي نظرة على المثال التالي، هنا سنستخدم <code>setInterval</code> و <code>setTimeout</code> استخدامهما الاعتيادي، حيث نمرر <strong>سلسلة</strong> كمعامل أول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_57" style=""><span class="pln">setInterval</span><span class="pun">(</span><span class="str">"logTime()"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
setTimeout</span><span class="pun">(</span><span class="str">"logMessage('"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> msgValue </span><span class="pun">+</span><span class="pln"> </span><span class="str">"')"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span></pre>

<p>
	ويكون الخيار الأفضل في هذه الحالة هو تمرير <strong>دالة</strong> كوسيط أولي مثل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2997_59" style=""><span class="pln">setInterval</span><span class="pun">(</span><span class="pln">logTime</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">   </span><span class="com">// Passing the logTime function to setInterval</span><span class="pln">

setTimeout</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">// Passing an anonymous function to setTimeout</span><span class="pln">
    logMessage</span><span class="pun">(</span><span class="pln">msgValue</span><span class="pun">);</span><span class="pln">     </span><span class="com">// (msgValue is still accessible in this scope)</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span></pre>

<h2 id="-5">
	مشكلة جافا سكريبت العاشرة: الفشل في استخدام الوضع الصارم
</h2>

<p>
	<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> (بما في ذلك استخدام <code>;'use strict'</code> في بداية ملفات جافا سكريبت المصدرية) هو وسيلة لفرض تحليل أكثر دقّة ومعالجة الأخطاء في الشيفرة البرمجية الخاصة بك في وقت التنفيذ أيضًا. كوسيلة لجعلها أكثر أمانًا. ورغم أن الفشل في استخدام الوضع الصارم لا يشكل "خطأً" حقيقيًا، إلا أنّ استخدامه يتزايد بشكلٍ كبير و<span ipsnoautolink="true">يتم تشجيعه</span> بشكلٍ كبير، كما يعدّ تجاهله أمرًا سيّئًا.
</p>

<p>
	هذه بعض الميّزات للوضع الصارم:
</p>

<ul>
	<li>
		<strong>يجعل تصحيح الأخطاء أسهل</strong>. يؤدي وجود الأخطاء في الشيفرة البرمجية التي كان من الممكن تجاهلها أو التي كانت ستفشل بصمت إلى إنشاء أخطاء أو رمي استثناءات، ما ينبهك بشكلٍ مسبق إلى مشاكل جافا سكريبت في مشروعك البرمجي ويوجهك بشكل أسرع إلى مصدرها.
	</li>
	<li>
		<strong>يمنع المتغيّرات العامة العرضية.</strong> يؤدي تعيين قيمة لمتغير غير معلن عنه تلقائيًا دون الوضع الصارم إلى إنشاء متغير عام بهذا الاسم. وهذا هو أحد أكثر أخطاء جافا سكريبت شيوعًا. وعند تفعيل الوضع الصارم يؤدي ذلك إلى إظهار خطأ.
	</li>
	<li>
		<strong>يوقف تغيير النوع التلقائي لـ <code>this</code></strong>. بدون الوضع الصارم، يفرض مرجع إلى قيمة <code>this</code> الخالية أو غير المحددة تلقائيًا إلى المتغير <code>globalThis</code>. يمكن أن يسبب هذا العديد من الأخطاء. بينما في الوضع الصارم، تؤدي الإشارة إلى هذه القيمة الخالية أو غير المحددة إلى ظهور خطأ.
	</li>
	<li>
		<strong>يمنع تكرار أسماء الخاصيات أو قيم المعاملات</strong>. يظهر الوضع الصارم خطأً عند تحديد اسمين مماثلين لخاصية كائنٍ واحد (مثال؛ <code>var object = {foo: “bar”, foo: “baz”};</code>) أو اسمًا مكرّرًا لدالّة (مثال؛ <code>function foo(val1, val2, val1){}</code>)، وبالتالي يساعد باكتشاف ما يكاد أن يكون خطأً في شيفرتك الذي ربما تكون قد أهدرت وقتًا طويلاً في تعقبه.
	</li>
	<li>
		<strong>يجعل <code>()eval</code> أكثر أمانًا</strong>. هناك بعض الاختلافات في الطريقة التي تتصرف بها الدالة <code>()eval</code> بين الوضعين الصارم وغير الصارم . والأهم من ذلك، في الوضع الصارم، <strong>لا</strong> يتم تُنشئ المتغيرات والدوال المعرّفة داخل تعليمة <code>()eval</code> في النطاق المحتوي. (بل <strong>تُنشأ</strong> في النطاق المحتوي في الوضع غير الصارم، الذي يمكن أن يكون أيضًا مصدرًا شائعًا لمشاكل جافا سكريبت).
	</li>
	<li>
		<strong>يعطي خطأً عند استخدامٍ خاطئٍ لـ <code>delete</code></strong>. لا يمكن استخدام عامل <code>delete</code> (الذي يستخدم لإزالة الخواص من الكائنات) على خواص كائنات غير قابلة للضبط nonconfigurable properties. ستفشل التعليمات البرمجية غير الصارمة بصمت عند إجراء محاولة لحذف خاصيةٍ غير قابلة للضبط، في حين أن الوضع الصارم سيعطي رسالة خطأ في هذه الحالة.
	</li>
</ul>

<h2 id="-6">
	التخفيف من مشاكل جافا سكريبت باستخدام نهج أكثر ذكاءً
</h2>

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

<h2 id="-7">
	أسئلة شائعة
</h2>

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

<h3>
	ما هي الأخطاء الشائعة في جافا سكريبت؟
</h3>

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

<h3>
	كيف يمكنني تطوير مهاراتي في جافا سكريبت؟
</h3>

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

<h3>
	لمَ أكتب شيفرة برمجية معرضة بالأخطاء؟
</h3>

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

<h3>
	هل جافا سكريبت كثيرة المشاكل؟
</h3>

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

<p>
	ترجمة -وبتصرف- لمقال <a href="https://www.toptal.com/javascript/10-most-common-javascript-mistakes" rel="external nofollow">The 10 Most Common JavaScript Issues Developers Face</a> لكاتبه Ryan J. Peterson
</p>

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

<ul>
	<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>
	<li>
		<a href="https://academy.hsoub.com/programming/java/%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%B9%D9%88%D8%A7%D9%85%D9%84-%D9%88%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-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-r380/" rel="">المتغيرات والعوامل والأخطاء البرمجية في لغة جافا</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC-%D8%A7%D9%84%D9%85%D8%AD%D8%AA%D8%B1%D9%81/" rel="">كيف تصبح مبرمجًا محترفًا</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2328</guid><pubDate>Fri, 17 May 2024 12:01:01 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x627;&#x644;&#x643;&#x631;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x631;&#x62A;&#x62F;&#x629; &#x627;&#x644;&#x645;&#x644;&#x648;&#x646;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x643;&#x627;&#x626;&#x646;&#x627;&#x62A; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A; -&#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x623;&#x648;&#x644;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%83%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B1%D8%AA%D8%AF%D8%A9-%D8%A7%D9%84%D9%85%D9%84%D9%88%D9%86%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r2323/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_05/-.png.6c725641e0d0bdc88d5c6eb8e7414db8.png" /></p>
<p>
	ألقينا نظرة في المقالات السابقة على النظرية اﻷساسية لكائنات جافا سكريبت وصياغتها بشيء من التفصيل كي تمتلك قاعدة صلبة تبنى عليها معارفك. وما سنفعله في هذا المقال هو التعمق أكثر من خلال تمرين تطبيقي للتمرن على بناء كائنات جافا سكريبت خاصة بك، وفيها سننشئ بعض الكرات الملونة المرتدة.
</p>

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

<ol>
	<li>
		<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>
	</li>
	<li>
		<p>
			<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>
	</li>
	<li>
		<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-%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/" rel="">أساسيات جافا سكريبت</a> كما شرحناها في سلسلة المقالات السابقة.
		</p>
	</li>
	<li>
		<p>
			أساسيات البرمجة كائنية التوجه في جافا سكريبت OOJS كما شرحناها في مقال <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%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-%D9%88%D8%AA%D8%AD%D9%82%D9%8A%D9%82%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2316/" rel="">أساسيات البرمجة كائنية التوجه في جافا سكريبت</a>، ومقال <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-prototype-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2310/" rel="">كائنات Prototype في جافا سكريبت</a>.
		</p>
	</li>
</ol>

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

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="149544" href="https://academy.hsoub.com/uploads/monthly_2024_05/01_bouncing-balls.png.8edbcacb15b085b4b317c8788363149d.png" rel=""><img alt="01 bouncing balls" class="ipsImage ipsImage_thumbnailed" data-fileid="149544" data-unique="5rr7bopvk" src="https://academy.hsoub.com/uploads/monthly_2024_05/01_bouncing-balls.thumb.png.be238a82771731e2d769443164411c33.png"> </a>
</p>

<p>
	يستخدم التطبيق الواجهة البرمجية <a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%B9%D9%86%D8%B5%D8%B1-canvas-%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%D8%A8%D8%AA-r207/" rel="">Canvas</a> لرسم الكرات على الشاشة، والواجهة لتحريك المشهد بأكمله. لا حاجة لأي معرفة مسبقة بالتعامل مع هذه الواجهات البرمجية، على أمل أن يدفعك العمل خلال فترة إنجاز التطبيق إلى استكشاف هاتين الواجهتين أكثر. ستستخدم أيضًا بعض الكائنات اﻷنيقة، ونستعرض تقنيات جميلة مثل جعل كرة ترتد عن جدار، والتحقق من تصادم كرتين (وتعرف باكتشاف التصادم collision detection).
</p>

<h2 id="-2">
	نقطة الانطلاق
</h2>

<p>
	لتبدأ العمل، انسخ الملفات <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/bouncing-balls/index.html" rel="external nofollow"><code>index.html</code></a> و <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/bouncing-balls/style.css" rel="external nofollow"><code>style.css</code></a> و <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/bouncing-balls/main.js" rel="external nofollow"><code>main.js</code></a> إلى حاسوبك، وتتضمن هذه الملفات:
</p>

<ol>
	<li>
		ملف HTML بسيط يضم العنصر <code>&lt;h1&gt;</code> والعنصر <code>&lt;canvas&gt;</code> لرسم الكرات وعناصر لتطبيق تنسيقات CSS وشيفرة جافا سكريبت على صفحة HTML.
	</li>
	<li>
		بعض التنسيقات البسيطة جدًا لتنسيق وضبط موقع العنصر، والتخلص من حواشي الصفحة وأشرطة التمرير لتظهر بمظهر أنيق.
	</li>
	<li>
		ملف يضم بعض شيفرة جافا سكريبت ﻹعداد العنصر <code>&lt;canvas&gt;</code> وتحضير دالة عامة سنستخدمها في التطبيق.
	</li>
</ol>

<p>
	يبدو القسم اﻷول من الشيفرة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5217_8" style=""><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">

</span><span class="kwd">const</span><span class="pln"> width </span><span class="pun">=</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"> window</span><span class="pun">.</span><span class="pln">innerWidth</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> height </span><span class="pun">=</span><span class="pln"> </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"> window</span><span class="pun">.</span><span class="pln">innerHeight</span><span class="pun">);</span></pre>

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

<p>
	نُعد تاليًا الثابتين <code>width</code> و <code>height</code> اللذين يمثلان اتساع وارتفاع لوحة الرسم (أي قيمتي الخاصيتين <code>canvas.width</code> و<code>canvas.height</code>) ليكونا مساويين لارتفاع واتساع نافذة عرض المتصفح (المنطقة التي تُعرض عليها صفحة الويب) ونحصل عليهما من التعليمتين <code>Window.innerWidth</code> و <code>Window.innerHeight</code>. لاحظ كيف ربطنا عدة عمليات إسناد معًا لتسريع عملية ضبط قيم المتغيرات، وهذا أمر صحيح تمامًا.
</p>

<p>
	لدينا بعد ذلك دالتين مساعدتين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5217_10" style=""><span class="kwd">function</span><span class="pln"> random</span><span class="pun">(</span><span class="pln">min</span><span class="pun">,</span><span class="pln"> max</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"> </span><span class="pun">(</span><span class="pln">max </span><span class="pun">-</span><span class="pln"> min </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"> min</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"> randomRGB</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">rgb</span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">)},</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">)},</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">)})`;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الأولى هي الدالة <code>()random</code> التي تأخذ وسيطين وتعيد عددًا عشوائيًا بين قيمتي الوسيطين، والثانية هي <code>()randomRGB</code> وتولّد لونًا عشوائيًا على شكل نص ناتج عن تنفيذ الدالة <code>()rgb</code>.
</p>

<h2 id="-3">
	نمذجة كرة في تطبيقنا
</h2>

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

<p>
	لنبدأ بإضافة تعريف الصنف التالي في نهاية الشيفرة الموجودة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5217_12" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Ball</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> velX</span><span class="pun">,</span><span class="pln"> velY</span><span class="pun">,</span><span class="pln"> color</span><span class="pun">,</span><span class="pln"> size</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">x </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velX </span><span class="pun">=</span><span class="pln"> velX</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velY </span><span class="pun">=</span><span class="pln"> velY</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">color </span><span class="pun">=</span><span class="pln"> color</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">size </span><span class="pun">=</span><span class="pln"> size</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<ul>
	<li>
		<code>x</code> و <code>y</code> هما الإحداثيين اﻷفقي والعمودي للنقطة التي تنطلق منها الكرة على الشاشة. يمكن أن تبدأ النقاط من النقطة (0,0) وهي أعلى ويسار نافذة العرض، حتى النقطة التي تمثل أقصى اتساع وأقصى ارتفاع لنافذة عرض المتصفح وهي أدنى ويمين نافذة العرض.
	</li>
	<li>
		السرعتين اﻷفقية <code>velX</code> والعمودية <code>velY</code>: إذ تُعطى لكل كرة سرعتين أفقية وعمودية. وما نفعله في الواقع هو إضافة هاتين القيمتين بانتظام إلى اﻹحداثيين <code>x</code> و <code>y</code> عند تحريك الكرة، وذلك لدفعها بهذا المقدار في كل إطار للحركة.
	</li>
	<li>
		اللون <code>color</code>: وهو اللون الذي تأخذه الكرة.
	</li>
	<li>
		القياس <code>size</code>: وهو قياس الكرة، ويُمثَّل بنصف قطرها.
	</li>
</ul>

<p>
	تمثل القيم السابقة خاصيات الكائن، لكن ماذا عن التوابع؟ فنحن نريد للكرات أن تسلك سلوكًا ما في التطبيق!
</p>

<h3 id="-4">
	رسم الكرة
</h3>

<p>
	أضف بداية التابع <code>()draw</code> إلى الصنف <code>Ball</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5217_14" style=""><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">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="kwd">this</span><span class="pun">.</span><span class="pln">color</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="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">size</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">
  ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<ul>
	<li>
		<p>
			نستخدم أولًا التابع <code>()beginPath</code> لنوضح أننا نريد رسم شكل ما على اللوحة.
		</p>
	</li>
	<li>
		<p>
			نستخدم تاليًا التابع <code>fillStyle</code> لنحدد لون الشكل، وضبطناه على قيمة الخاصية <code>color</code> للكرة.
		</p>
	</li>
	<li>
		<p>
			نستخدم بعدها التابع <code>()arc</code> لرسم قوس على الصفحة، وللتابع المعاملات التالية:
		</p>
	</li>
	<li>
		<p>
			<code>x</code> و <code>y</code>: وهما إحداثيا مركز القوس، ونضبطهما من قبل الخاصيتين <code>x</code> و <code>y</code> للكرة.
		</p>
	</li>
	<li>
		<p>
			نصف قطر القوس: ونضبطه على قيم الخاصية <code>size</code> للكرة.
		</p>
	</li>
	<li>
		<p>
			يحدد آخر معاملين زاوية بداية ونهاية القوس على الدائرة (مقدرين بالراديان). وفي حالتنا كانت قيمة البداية 0 والنهاية <code>2*PI</code> التي تعادل 360 درجة. وهكذا سنتمكن من رسم كامل الدائرة، ولو كانت النهاية <code>PI</code> سنحصل على نصف دائرة (180 درجة).
		</p>
	</li>
	<li>
		<p>
			نستخدم أخيرًا التابع <code>()fill</code> والذي يقتضي مبدئيًا إنهاء رسم المسار الذي بدأه التابع <code>()beginPath</code> ومن ثم ملئ المساحة الناتجة باللون الذي خصصناه باستخدام التابع <code>fillStyle</code>.
		</p>
	</li>
</ul>

<p>
	بإمكانك اختبار الكائن اﻵن:
</p>

<ol>
	<li>
		<p>
			احفظ التغييرات التي أجريتها على الشيفرة وأعد تحميل ملف HTMl.
		</p>
	</li>
	<li>
		<p>
			افتح طرفية جافا سكريبت في المتصفح وأعد تحميل الصفحة كي تأخذ لوحة الرسم أبعاد نافذة عرض المتصفح الجديدة والتي تكون أصغر من اﻷصلية لأنها تُعرض مع الطرفية.
		</p>
	</li>
	<li>
		<p>
			اكتب الشيفرة التالية ﻹنشاء نسخة عن الكائن <code>Ball</code>:
		</p>
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5217_16" style=""><span class="kwd">const</span><span class="pln"> testBall </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Ball</span><span class="pun">(</span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</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">4</span><span class="pun">,</span><span class="pln"> </span><span class="str">"blue"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span></pre>

<ol start="4">
	<li>
		جرب استدعاء عناصر الكائن:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5217_18" style=""><span class="pln">testBall</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
testBall</span><span class="pun">.</span><span class="pln">size</span><span class="pun">;</span><span class="pln">
testBall</span><span class="pun">.</span><span class="pln">color</span><span class="pun">;</span><span class="pln">
testBall</span><span class="pun">.</span><span class="pln">draw</span><span class="pun">();</span></pre>

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

<h3 id="-5">
	تحديث بيانات الكرة
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5217_20" style=""><span class="pln">update</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">x </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">size</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;=</span><span class="pln"> width</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">velX </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">velX</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">x </span><span class="pun">-</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">size</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;=</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="kwd">this</span><span class="pun">.</span><span class="pln">velX </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">velX</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">y </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">size</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;=</span><span class="pln"> height</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">velY </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">velY</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">y </span><span class="pun">-</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">size</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;=</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="kwd">this</span><span class="pun">.</span><span class="pln">velY </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">velY</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">x </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velX</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velY</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	نتحقق في أربع حالات إذا ما كان:
</p>

<ul>
	<li>
		اﻹحداثي <code>x</code> أكبر من اتساع لوحة الرسم، ويعني ذلك تجاوز الكرة إلى أقصى يمين اللوحة.
	</li>
	<li>
		اﻹحداثي <code>x</code> أصغر من 0، ويعني ذلك أن تجاوز الكرة إلى أقصى يسار اللوحة.
	</li>
	<li>
		اﻹحداثي <code>y</code> أكبر من ارتفاع لوحة الرسم، ويعني ذلك تجاوز الكرة إلى أسفل لوحة الرسم.
	</li>
	<li>
		اﻹحداثي <code>y</code> أصغر من 0، ويعني ذلك تجاوز الكرة إلى أعلى اللوحة.
	</li>
</ul>

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

<p>
	يضيف السطرين اﻷخيرن قيمتي <code>velX</code> و <code>velY</code> إلى قيمتي <code>x</code> و <code>y</code>على الترتيب كي تتحرك الكرة كل مرة نستدعي فيها هذا التابع.
</p>

<p>
	ما فعلناه كافٍ حتى اللحظة، لننتقل الآن إلى مرحلة تحريك الرسوم.
</p>

<h2 id="-6">
	تحريك الكرة
</h2>

<p>
	سنبدأ اﻵن إضافة كرات إلى لوحة الرسم وتحريكها. ونحتاج بداية إلى إنشاء مكان نُخزن فيه كل الكرات ثم نطلقها، والشيفرة التالية ستؤدي المطلوب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5217_22" style=""><span class="kwd">const</span><span class="pln"> balls </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">balls</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">25</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"> size </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> ball </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Ball</span><span class="pun">(</span><span class="pln">
    </span><span class="com">// تُرسم الكرات دائمًا في موقع يبعد على اﻷقل مقدار اتساع كرة</span><span class="pln">
    </span><span class="com">// عن حافة لوحة الرسم لتفادي أية أخطاء</span><span class="pln">
    random</span><span class="pun">(</span><span class="lit">0</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> size</span><span class="pun">,</span><span class="pln"> width </span><span class="pun">-</span><span class="pln"> size</span><span class="pun">),</span><span class="pln">
    random</span><span class="pun">(</span><span class="lit">0</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> size</span><span class="pun">,</span><span class="pln"> height </span><span class="pun">-</span><span class="pln"> size</span><span class="pun">),</span><span class="pln">
    random</span><span class="pun">(-</span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">),</span><span class="pln">
    random</span><span class="pun">(-</span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">),</span><span class="pln">
    randomRGB</span><span class="pun">(),</span><span class="pln">
    size</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">);</span><span class="pln">

  balls</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">ball</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُنشئ الحلقة <code>while</code> نسخة جديدة من الكائن باستخدام قيم عشوائية تولّدها الدالتان المساعدتان <code>()random</code> و <code>()randomRGB</code> ثم نستخدم التابع <code>()push</code> لدفع الكرة الناتجة إلى نهاية مصفوفة الكرات، طالما أن عدد الكرات في المصفوفة أقل من 25 كرة. بإمكانك تغيير عدد الكرات اﻷعظمي في المصفوفة من التعليمة <code>balls.length &lt; 25</code> وذلك وفقًا لقدرة المعالجة التي يتمتع بها حاسوبك ومتصفحك، فاختيار عدة آلاف من الكرات قد تبطئ حركة الرسوم.
</p>

<p>
	أضف تاليًا الشيفرة التالية إلى نهاية الشيفرة الموجودة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5217_24" style=""><span class="kwd">function</span><span class="pln"> loop</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">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(0 0 0 / 25%)"</span><span class="pun">;</span><span class="pln">
  ctx</span><span class="pun">.</span><span class="pln">fillRect</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"> width</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">const</span><span class="pln"> ball </span><span class="kwd">of</span><span class="pln"> balls</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    ball</span><span class="pun">.</span><span class="pln">draw</span><span class="pun">();</span><span class="pln">
    ball</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">

  requestAnimationFrame</span><span class="pun">(</span><span class="pln">loop</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<ul>
	<li>
		يضبط لون خلفية لوحة الرسم على لون أسود وتتكون نصف شفافة، ومن ثم ترسم مربعًا من نفس اللون ليغطي أبعاد اللوحة باستخدام التابع <code>()fillRectangle</code> (معاملاته هي إحداثيات نقطة بداية المربع واتساعه وارتفاعه). أما وظيفية هذا المربع فهو تغطية الإطار السابق قبل رسم الإطار التالي. فإن لم نفعل ذلك سنرى أفاعي طويلة تلتف ضمن اللوحة بدلًا من كرات تتحرك. أما سبب اللون نصف الشفاف للخلفية <code>( 25% / 0 0 0)rgb</code>، فهو السماح للإطار السابق أن يظهر بشكل طفيف خلف اﻹطار الحالي لتعطي أثرًا خلف الكرة المتحركة. وإن جعلت قيمة الشفافية 1 بدلًا من 0.25، فلن ترى هذا اﻷثر. حاول أن تغير هذه القيمة وراقب ما يحدث.
	</li>
	<li>
		تتنقل بين جميع الكرات في مصفوفة الكرات <code>balls</code>، وينفّذ الدالتين <code>()draw</code> و <code>()update</code> لرسم كل كرة على الشاشة، ثم تنفّذ التحديثات اللازمة للموقع والسرعة في الوقت المناسب للإطار التالي.
	</li>
	<li>
		تشغّل نفسها مجددًا باستخدام التابع <code>()requestAnimationFrame</code> الذي يُنفَّذ تكرارًا، وتُمرر له الدالة نفسها. ينفّذ التابع الدالة عدة مرات بالثانية لتكوين رسوميات متحركة سلسلة. وهذه العملة تُنفَّذ عادة بطريقة تعاودية recursively، أي تستدعي الدالة نفسها في كل مرة تُنفَّذ فيها، وهكذا تُنفَّذ مرارًا وتكرارًا.
	</li>
</ul>

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

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

<p>
	هذا هو المطلوب بدايةً، جرّب حفظ التغييرات التي أجريتها واختبر الكرات المرتدة.
</p>

<h2 id="-7">
	إضافة آلية لالتقاط التصادم بين الكرات
</h2>

<p>
	سنضيف اﻵن آلية لاكتشاف التصادم بين الكرات في تطبيقنا، كي تعرف كراتنا أنها تصطدم ببعضها.
</p>

<p>
	أضف بداية التابع التالي لى الصنف <code>Ball</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5217_28" style=""><span class="pln">collisionDetect</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"> ball </span><span class="kwd">of</span><span class="pln"> balls</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="pln"> </span><span class="pun">!==</span><span class="pln"> ball</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"> dx </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">-</span><span class="pln"> ball</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> dy </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">-</span><span class="pln"> ball</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> distance </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">dx </span><span class="pun">*</span><span class="pln"> dx </span><span class="pun">+</span><span class="pln"> dy </span><span class="pun">*</span><span class="pln"> dy</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">distance </span><span class="pun">&lt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">size </span><span class="pun">+</span><span class="pln"> ball</span><span class="pun">.</span><span class="pln">size</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        ball</span><span class="pun">.</span><span class="pln">color </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">color </span><span class="pun">=</span><span class="pln"> randomRGB</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>

<ul>
	<li>
		<p>
			نتحقق من أجل كل كرة إذا ما اصطدمت بالكرة الحالية. ولتنفيذ اﻷمر نبدأ حلقة <code>for...of</code> جديدة للتنقل بين جميع كرات المصفوفة <code>[]balls</code>.
		</p>
	</li>
	<li>
		<p>
			نستخدم مباشرة في الحلقة <code>for</code> العبارة <code>if</code> للتحقق من أن الكرة التي وصلنا إليها هي نفسها الكرة الحالية التي نتفحصها. ولأننا لا نريد أن نتحقق إن اصطدمت كرة بنفسها، نتحقق أن الكرة الحالية (وهي الكرة التي استدعت التابع <code>()collisonDetect</code>) هي نفسها الكرة التي وصلنا إليها في هذا التكرار من تكرارات الحلقة. نستخدم بعد ذلك عامل النفي <code>!</code> في عبارة التحقق <code>this !== ball</code> كي لا تُنفَّذ الشيفرة داخل <code>if</code> إلا إن لم تكن الكرة هي نفسها.
		</p>
	</li>
	<li>
		<p>
			نستخدم بعد ذلك خوارزمية شائعة للتحقق من التصادم بين كرتين، وذلك عن طريق التحقق من تداخل مساحتي الكرتين.
		</p>
	</li>
	<li>
		<p>
			إن اكتُشف التصادم، تُنفَّذ الشيفرة ضمن عبارة <code>if</code> الثانية. وفي هذه الحالة نغيّر فقط لوني الكرتين المتصادمتين عشوائيًا. بإمكاننا أيضًا تعقيد التطبيق بجعل الكرات ترتد عن بعضها كما يجري اﻷمر في الواقع، لكن ذلك صعب التنفيذ. ولمحاكاة هذه العمليات الفيزيائية، يميل المطورّون إلى استخدام مكتبات جاهزة مثل <code>Physics</code> و <code>mattre</code> و <code>Phaser</code> وغيرها.
		</p>
	</li>
</ul>

<p>
	لا بد أيضًا من استدعاء هذه الدالة من أجل كل إطار من إطارات المشهد المتحرك. عدّل الدالة لتستدعي التابع <code>()ball.collisionDetect</code> بعد التابع <code>()ball.update</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5217_30" style=""><span class="kwd">function</span><span class="pln"> loop</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">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(0 0 0 / 25%)"</span><span class="pun">;</span><span class="pln">
  ctx</span><span class="pun">.</span><span class="pln">fillRect</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"> width</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">const</span><span class="pln"> ball </span><span class="kwd">of</span><span class="pln"> balls</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    ball</span><span class="pun">.</span><span class="pln">draw</span><span class="pun">();</span><span class="pln">
    ball</span><span class="pun">.</span><span class="pln">update</span><span class="pun">();</span><span class="pln">
    ball</span><span class="pun">.</span><span class="pln">collisionDetect</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  requestAnimationFrame</span><span class="pun">(</span><span class="pln">loop</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	<strong>ملاحظة</strong>: إن واجهت صعوبة في تنفيذ هذا التطبيق، تستطيع مقارنة ما فعلته مع <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/bouncing-balls/main-finished.js" rel="external nofollow">النسخة الجاهزة</a> من الشيفرة، ويمكنك أيضًا تجريب <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/bouncing-balls/main-finished.js" rel="external nofollow">النسخة العاملة</a>.
</p>

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

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

<p>
	ترجمة -وبتصرف- للمقال: <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_building_practice" rel="external nofollow">Object building practice</a>
</p>

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2317/" rel="">تعريف الأصناف في جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%B4%D8%B1%D9%88%D8%B9-%D9%84%D8%B9%D8%A8%D8%A9-%D9%85%D9%86%D8%B5%D8%A9-%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%D8%A8%D8%AA-r1355/" rel="">مشروع لعبة منصة باستخدام جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%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%D9%8A%D8%A8%D8%AA-r1354/" rel="">معالجة الأحداث في جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/css/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%B1%D8%B3%D9%88%D9%85-%D9%85%D8%AA%D8%AD%D8%B1%D9%83%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-css-r1340/" rel="">إنشاء رسوم متحركة باستخدام CSS</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2323</guid><pubDate>Thu, 16 May 2024 12:00:02 +0000</pubDate></item><item><title>&#x627;&#x644;&#x639;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x628;&#x635;&#x64A;&#x63A;&#x629; JSON &#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%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A8%D8%B5%D9%8A%D8%BA%D8%A9-json-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2318/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_05/JSON.png.9ce07a293d3e9df90432bf1f7be9624e.png" /></p>
<p>
	تُعد صيغة جافاسكريبت لترميز الكائنات JavaScript Object Notation واختصارًا JSON صيغة نصية لتمثيل البيانات المهيكلة وفقًا للصياغة الكائنية في جافاسكريبت، وهي شائعة الاستخدام لتمثيل وتبادل المعطيات عبر الويب (مثل إرسال البيانات من الخادم إلى العميل لتُعرض على صفحة الويب). ستصادف هذه الصيغة كثيرًا لهذا سنشرح لك في هذا المقال ما تحتاج معرفته عن عمل JSON في جافاسكربت بما في ذلك تفسير صياغتها للوصول إلى البيانات التي تضمها وكتابة بياناتك الخاصة بهذه الصياغة.
</p>

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

<ol>
	<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>
	<li>
		أساسيات البرمجة كائنية التوجه كما شرحناها في مقال <a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-r2305/" rel="">أساسيات العمل مع الكائنات في جافا سكريبت.</a>
	</li>
</ol>

<h2 id="json-1">
	ماهي صيغة JSON؟
</h2>

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

<p>
	لتنسيق JSON طبيعة نصية، وهو أمر مفيد لنقل البيانات عبر الشبكات. وتحتاج إلى تحويل تنسيق JSON إلى كائن جافا سكريبت أصلي إن أردت الوصول إلى محتوياته. وبالطبع، لن يكون اﻷمر صعبًا لوجود<a href="https://wiki.hsoub.com/JavaScript/JSON" rel="external"> كائن JSON </a>عام في جافا سكريبت يقدّم توابع للتحويل بين الصيغتين (JSON - كائن جافا سكريبت).
</p>

<p>
	<strong>ملاحظة</strong>: تُدعى عملية تحويل كائن إلى نص بغية إرساله عبر شبكة بالسَلسَلة serialization، وعملية تحويل سلسلة نصية إلى كائن أصلي إلغاء السَلسَلة deserialization.
</p>

<p>
	يمكن تخزين نص JSON في ملف خاص، وسيكون على شكل ملف نصي نمطي يحمل اللاحقة <code>json.</code>، وله نمط <a href="https://developer.mozilla.org/en-US/docs/Glossary/MIME_type" rel="external nofollow">MIME</a> التالي: <code>application/json</code>.
</p>

<h3 id="json-2">
	هيكلية JSON
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9352_9" style=""><span class="pun">{</span><span class="pln">
  </span><span class="str">"squadName"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Super hero squad"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"homeTown"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Metro City"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"formed"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2016</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"secretBase"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Super tower"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"active"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"members"</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">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Molecule Man"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"age"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">29</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"secretIdentity"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Dan Jukes"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"powers"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Radiation resistance"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Turning tiny"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Radiation blast"</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">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Madame Uppercut"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"age"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">39</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"secretIdentity"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Jane Wilson"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"powers"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="str">"Million tonne punch"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"Damage resistance"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"Superhuman reflexes"</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">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Eternal Flame"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"age"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1000000</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"secretIdentity"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Unknown"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"powers"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="str">"Immortality"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"Heat Immunity"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"Inferno"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"Teleportation"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"Interdimensional travel"</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>superHeroes</code> مثلًا، سنتمكن من الوصول إلى البيانات التي يضمها وفق أسلوب الوصول إلى أعضاء الكائنات (نقطة أو قوس مربع). إليك مثالًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9352_11" style=""><span class="pln">superHeroes</span><span class="pun">.</span><span class="pln">homeTown</span><span class="pun">;</span><span class="pln">
superHeroes</span><span class="pun">[</span><span class="str">"active"</span><span class="pun">];</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9352_13" style=""><span class="pln">superHeroes</span><span class="pun">[</span><span class="str">"members"</span><span class="pun">][</span><span class="lit">1</span><span class="pun">][</span><span class="str">"powers"</span><span class="pun">][</span><span class="lit">2</span><span class="pun">];</span></pre>

<ol>
	<li>
		نستخدم اولًا اسم المتغير <code>superHeroes</code>..
	</li>
	<li>
		ندخل بعدها إلى الخاصية <code>members</code> ضمنه، لهذا نستخدم التعليمة <code>["members"]</code>.
	</li>
	<li>
		تضم الخاصية <code>members</code> مصفوفة كائنات، وعلينا الوصول إلى الكائن الثاني منها لهذا نستخدم الأمر <code>[1]</code>.
	</li>
	<li>
		وضمن الكائن الثاني من المصفوفة، نريد الوصول إلى الخاصية <code>powers</code>، لهذا نستخدم التعليمة <code>["powers"]</code>.
	</li>
	<li>
		تضم الخاصية <code>powers</code> مصفوفة تحتوي على القوى الخارقة للأبطال، ونريد من بينها الثالثة <code>[2]</code>.
	</li>
</ol>

<p>
	<strong>ملاحظة</strong>: يمكنك الوصول إلى البيانات السابقة بتنسيق JSON ضمن الملف <a href="https://mdn.github.io/learning-area/javascript/oojs/json/JSONTest.html" rel="external nofollow">JSONTest.html</a> (ألق نظرة على <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/json/JSONTest.html" rel="external nofollow">الشيفرة المصدرية</a>). جرّب أن تحمّل الملف ثم الوصول إلى البيانات ضمن المتغيّر عبر طرفية جافا سكريبت في متصفحك.
</p>

<h3 id="json-3">
	المصفوفات وتنسيق JSON
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9352_15" style=""><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Molecule Man"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"age"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">29</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"secretIdentity"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Dan Jukes"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"powers"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Radiation resistance"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Turning tiny"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Radiation blast"</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">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Madame Uppercut"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"age"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">39</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"secretIdentity"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Jane Wilson"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"powers"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      </span><span class="str">"Million tonne punch"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"Damage resistance"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"Superhuman reflexes"</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>
	هذه الشيفرة نص JSON صحيح تمامًا، وعليك فقط الوصول إلى أعضاء المصفوفة (في النسخة المفسّرة منه) بأن تبدأ بدليل العنصر الذي تريده من المصفوفة مثل<br>
	<code>[0]["powers"][0]</code>.
</p>

<h3 id="">
	ملاحظات أخرى
</h3>

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

<h2 id="json-4">
	تطبيق عملي: العمل مع JSON
</h2>

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

<h3 id="-1">
	نقطة الانطلاق
</h3>

<p>
	أنشئ بداية نسخة عن الملفين <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/json/heroes.html" rel="external nofollow">heroes.html</a> و <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/json/style.css" rel="external nofollow">style.css</a> على حاسوبك. ويتضمن الملف الثاني بعض تنسيقات CSS البسيطة لتنسيق الصفحة، بينما يضم اﻷول شيفرة HTML بسيطة لجسم الصفحة، إضافة إلى العنصر <code>&lt;script&gt;</code> الذي يضم شيفرة جافا سكريبت التي سنكتبها خلال عملنا على هذا التمرين.
</p>

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

</span><span class="tag">&lt;section&gt;</span><span class="pln">
...
</span><span class="tag">&lt;/section&gt;</span><span class="pln">

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

<p>
	تتوفر بيانات JSON للتمرين ضمن <a href="https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json" rel="external nofollow">ملف مخصص</a> على جيت-هب، وسنحمّل هذا الملف باستخدام الشيفرة ونستخدم بعض دوال شجرة DOM لعرض البيانات:
</p>

<p style="text-align: center;">
	<img alt="01_json-superheroes.png" class="ipsImage ipsImage_thumbnailed" data-fileid="149201" data-ratio="63.77" data-unique="009hxicz8" style="width: 600px; height: auto;" width="839" src="https://academy.hsoub.com/uploads/monthly_2024_05/01_json-superheroes.png.e9b4a7e79258188b47b31eb9c3a9bc48.png">
</p>

<h3 id="-2">
	دوال المستوى اﻷعلى
</h3>

<p>
	وهي كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9352_20" style=""><span class="kwd">async</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> populate</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"> 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">const</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">Request</span><span class="pun">(</span><span class="pln">requestURL</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">request</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> superHeroes </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">json</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">
  populateHeroes</span><span class="pun">(</span><span class="pln">superHeroes</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نستخدم للحصول على بيانات JSON واجهة برمجية تُدعى <code>Fetch</code> تسمح لنا بإرسال طلبات عبر اﻹنترنت للحصول على موارد من الخادم من خلال جافا سكريبت (مثل الصور والنصوص وملفات JSON وحتى مقتطفات من شيفرة HTML). أي بإمكاننا تحديث جزء صغير من محتوى الصفحة بدلًا من اعادة تحميل الصفحة بالكامل.
</p>

<p>
	تستخدم اﻷسطر اﻷربعة اﻷولى من الدالة الواجهة البرمجية <code>Fetch</code> ﻹحضار ملف JSON من الخادم:
</p>

<ul>
	<li>
		صرحنا عن المتغير <code>requestURL</code> لتخزين عنوان الملف على جيت-هب.
	</li>
	<li>
		استخدمنا عنوان URL لتهيئة كائن الطلب <code>Request</code> الجديد.
	</li>
	<li>
		أرسلنا طلب عبر اﻹنترنت باستخدام الدالة <code>()fetch</code> وسيعيد ذلك كائن استجابة <code>Response</code>.
	</li>
	<li>
		نحصل على الاستجابة بتنسيق JSON عن طريق استخدام الدالة <code>()json</code> العائدة للكائن <code>Response</code>.
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: الواجهة البرمجية <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%84%D8%A7%D8%AA%D8%B2%D8%A7%D9%85%D9%86-%D9%88%D8%A7%D9%84%D8%A7%D9%86%D8%AA%D8%B8%D8%A7%D8%B1-asyncawait-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r921/" rel="">غير متزامنة asynchronous</a>، لهذا لابد من إضافة الكلمة المحجوزة <code>async</code> قبل اسم الدالة التي تستخدم الواجهة والكلمة المحجوزة <a href="https://wiki.hsoub.com/JavaScript/await" rel="external">await</a> قبل استدعاء أية دوال غير متزامنة.
</p>

<p>
	بعد كل ذلك، سيضم المتغير <code>superHeroes</code> كان جافا سكريبت المبني وفق بيانات JSON. ثم نمرر بعد ذلك الكائن إلى استدعاء دالتين الأولى لتملأ العنصر <code>&lt;header&gt;</code> بالبيانات الصحيحة، والثانية لتنشئ بطاقة معلومات لكل بطل في الفريق ووضعها ضمن العنصر <code>&lt;section&gt;</code>.
</p>

<h3 id="-3">
	ترتيب المعلومات في الترويسة
</h3>

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

<pre class="ipsCode">function populateHeader(obj) {
  const header = document.querySelector("header");
  const myH1 = document.createElement("h1");
  myH1.textContent = obj.squadName;
  header.appendChild(myH1);

  const myPara = document.createElement("p");
  myPara.textContent = `Hometown: ${obj.homeTown} // Formed: ${obj.formed}`;
  header.appendChild(myPara);
}
</pre>

<p>
	تنشئ الشيفرة السابقة بداية عنصر <code>&lt;h1&gt;</code> باستخدام التابع <code>()createElement</code>، وأسندنا إلى محتواه قيمة الخاصية <code>squadName</code> التي تعود إلى كائن جافا سكريبت، ثم ألحقنا العنصر ومحتواه بالترويسة مستخدمين التابع <code>()appendChild</code>. كررنا بعد ذلك نفس الخطوات مع الفقرة النصية، إذ أنشأناها بداية ثم وضعنا فيها المحتوى المناسب وألحقناها بالترويسة. والفرق الوحيد بين الحالتين هو أننا ضبطنا المحتوى النصي للفقرة ليكون مساويًا لقالب مفسّر (أو حرفي) template literal يضم قيمتي الخاصيتين <code>homeTown</code> و <code>formed</code>.
</p>

<h3 id="-4">
	إنشاء بطاقة معلومات البطل الخارق
</h3>

<p>
	أضف اﻵن شيفرة الدالة التي تُنشئ وتعرض بطاقة البطل إلى نهاية الشيفرة السابقة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9352_23" style=""><span class="kwd">function</span><span class="pln"> populateHeroes</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">
  </span><span class="kwd">const</span><span class="pln"> section </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">"section"</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> heroes </span><span class="pun">=</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">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="kwd">const</span><span class="pln"> myArticle </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">"article"</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> myH2 </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">"h2"</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> myPara1 </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">
    </span><span class="kwd">const</span><span class="pln"> myPara2 </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">
    </span><span class="kwd">const</span><span class="pln"> myPara3 </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">
    </span><span class="kwd">const</span><span class="pln"> myList </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">"ul"</span><span class="pun">);</span><span class="pln">

    myH2</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> hero</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span><span class="pln">
    myPara1</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">Secret</span><span class="pln"> identity</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">hero</span><span class="pun">.</span><span class="pln">secretIdentity</span><span class="pun">}`;</span><span class="pln">
    myPara2</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">Age</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">hero</span><span class="pun">.</span><span class="pln">age</span><span class="pun">}`;</span><span class="pln">
    myPara3</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Superpowers:"</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">const</span><span class="pln"> superPowers </span><span class="pun">=</span><span class="pln"> hero</span><span class="pun">.</span><span class="pln">powers</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"> power </span><span class="kwd">of</span><span class="pln"> superPowers</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"> power</span><span class="pun">;</span><span class="pln">
      myList</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">

    myArticle</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">myH2</span><span class="pun">);</span><span class="pln">
    myArticle</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">myPara1</span><span class="pun">);</span><span class="pln">
    myArticle</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">myPara2</span><span class="pun">);</span><span class="pln">
    myArticle</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">myPara3</span><span class="pun">);</span><span class="pln">
    myArticle</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">myList</span><span class="pun">);</span><span class="pln">

    section</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">myArticle</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بدأنا بتخزين قيمة الخاصية <code>members</code> لكائن جافا سكريبت في متغير جديد. وهذه الخاصية هي مصفوفة تضم عدة كائنات تضم معلومات عن كل بطل. ثم تنقلنا بين كائنات الخاصية باستخدام حلقة <code>for...of</code> لـِ:
</p>

<ol>
	<li>
		إنشاء عدة عناصر HTML جديدة وهي: <code>&lt;article&gt;</code> و <code>&lt;h2&gt;</code> وثلاث فقرات نصية <code>&lt;p&gt;</code> و <code>&lt;ul&gt;</code>.
	</li>
	<li>
		ضبط محتوى <code>&lt;h2&gt;</code> ليضم اسم البطل <code>name</code>.
	</li>
	<li>
		ملئ الفقرات النصية الثلاث بقيم الخاصيتين <code>secretIdentity</code> و <code>age</code> وبعبارة "Superpowers" لتقديم المعلومات الموجودة في القائمة.
	</li>
	<li>
		تخزين قيمة الخاصية <code>powers</code> في متغير آخر جديد يُدعى <code>superPowers</code> وتضم الخاصية مصفوفة تضم القوى الخارقة التي يتمتع بها البطل.
	</li>
	<li>
		استخدام حلقة <code>for...of</code> من جديد للتنقل بين القوى التي يمتلكها البطل وإنشاء عنصر <code>&lt;li&gt;</code> لوضع القوة ضمنه ثم نلحق عنصر القائمة <code>listItem</code> بالقائمة غير المرتبة <code>&lt;ul&gt;</code> (التس تُسمى <code>&lt;myList</code>).
	</li>
	<li>
		إلحاق العنصر <code>&lt;h2&gt;</code> والفقرات النصية الثلاث <code>&lt;p&gt;</code> والقائمة <code>&lt;ul&gt;</code> بالعنصر <code>&lt;article&gt;</code> (الذي يُسمى <code>myArticle</code>) وإلحاقه بالعنصر <code>&lt;section&gt;</code>. وانتبه إلى إلحاق العناصر وفق الترتيب السابق تمامًا، فسيعكس ذلك ترتيب الملعومات التي ستُعرض في صفحة HTML.
	</li>
</ol>

<p>
	<strong>ملاحظة</strong>: إن واجهت صعوبة في تنفيذ التمرين، عُد إلى <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/json/heroes-finished.html" rel="external nofollow">الشيفرة المصدرية</a> له أو اطلع على <a href="https://mdn.github.io/learning-area/javascript/oojs/json/heroes-finished.html" rel="external nofollow">النسخة الجاهزة</a> منه.
</p>

<p>
	<strong>ملاحظة</strong>: إن واجهت صعوبة في استيعاب استخدام ترميز (النقطة والأقواس المربعة) في الوصول إلى كائنات جافا سكريبت، سيساعدك فتح الملف <a href="https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json" rel="external nofollow">superheroes.json</a> في نافذة أخرى لمحررك النصي والرجوع إليه عند متابعة شيفرة جافا سكريبت. كما يمكنك العودة إلى مقال أساسيات العمل مع الكائنات في جافا سكريبت لمعلومات أوضح عن طريقة الترميز هذه.
</p>

<h3 id="-5">
	استدعاء توابع المستوى اﻷعلى
</h3>

<p>
	علينا أخيرًا استدعاء الدالة الأعلى مستوى <code>()populate</code>
</p>

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

<h2 id="-6">
	التحويل بين الكائنات والنصوص
</h2>

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

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

<ul>
	<li>
		<code>()parse</code>: يقبل نص JSON كمعامل ويعيد كائن جافا سكريبت الموافق.
	</li>
	<li>
		<code>()stringify</code>: يقبل كائنًا كمعامل له، ويعيد نص JSON الموافق.
	</li>
</ul>

<p>
	بإمكانك رؤية عمل التابع الأول في النسخة الجاهزة من التمرين السابق (انظر أيضًا إلى شيفرته المصدرية) وهو يفعل تمامًا ما تفعله النسخة التي بنيناها باستثناء أننا:
</p>

<ul>
	<li>
		حصلنا على الاستجابة على شكل سلسلة نصية بدلًا من تنسيق JSON لاستخدامنا التابع <code>()text</code> للحصول على الاستجابة.
	</li>
	<li>
		استخدمنا التابع <a href="https://wiki.hsoub.com/JavaScript/JSON/parse" rel="external">()parse</a> لتحويل النص إلى كائن جافا سكريبت.
	</li>
</ul>

<p>
	إليك مقطع الشيفرة الموافق لما ذكرنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9352_29" style=""><span class="kwd">async</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> populate</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"> 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">const</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">Request</span><span class="pun">(</span><span class="pln">requestURL</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</span><span class="pln"> fetch</span><span class="pun">(</span><span class="pln">request</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> superHeroesText </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">await</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">text</span><span class="pun">();</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> superHeroes </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">superHeroesText</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">
  populateHeroes</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><a href="https://wiki.hsoub.com/JavaScript/JSON/stringify" rel="external">()stringify</a></code> بطريقة معكوسة. جرّب اﻵن إدخال اﻷسطر التالية إلى طرفية جافا سكريبت في متصفحك سطرًا تلو اﻵخر:
</p>

<pre class="ipsCode">let myObj = { name: "Chris", age: 38 };
myObj;
let myString = JSON.stringify(myObj);
myString;
</pre>

<p>
	ننشئ هنا كائن جافا سكريبت ثم نتحقق من محتواه ونحوّله بعدها إلى نص JSON باستخدام التابع <code>()stringify</code>. نخزّن القيمة المعادة في متغيّر جيد ثم نتحقق منه مجددًا.
</p>

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

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

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

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

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel="">تعلم JSON</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%B5%D9%8A%D8%BA%D8%A9-json-%D9%88%D8%AA%D9%88%D8%A7%D8%A8%D8%B9%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-r826/" rel="">صيغة JSON وتوابعها في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D9%85%D8%A7-%D8%B9%D9%84%D9%8A%D9%83-%D9%85%D8%B9%D8%B1%D9%81%D8%AA%D9%87-%D8%B9%D9%86-%D8%AD%D9%82%D9%88%D9%84-json-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-mysql-r340/" rel="">ما عليك معرفته عن حقول JSON في قواعد بيانات MySQL</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%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%B5%D9%8A%D8%BA%D8%A9-json-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-go-r2165/" rel="">كيفية استخدام صيغة JSON في لغة Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2318</guid><pubDate>Fri, 10 May 2024 12:01:01 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x631;&#x64A;&#x641; &#x627;&#x644;&#x623;&#x635;&#x646;&#x627;&#x641; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2317/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_05/2146651569_.png.e1381210742003e8e62740c0e222d0ef.png" /></p>
<p>
	قدمنا في مقال سابق مدخلًا إلى <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%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-%D9%88%D8%AA%D8%AD%D9%82%D9%8A%D9%82%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2316/" rel="">مفاهيم البرمجة كائنية التوجه في جافا سكريبت</a>، وناقشنا مثالًا عن استخدام مبادئها لنمذجة مدرسين وطلاب في مدرسة. كما تحدثنا أيضًا عن إمكانية استخدام الكائنات المجردة prototype والدوال البانية constructor لتنفيذ نماذج مشابهة، والميزات المرتبطة بمفاهيم البرمجة غرضية التوجه التقليدية التي تقدمها جافا سكريبت.
</p>

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

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

<ol>
	<li>
		<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>
	</li>
	<li>
		<p>
			<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>
	</li>
	<li>
		<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-%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/" rel="">أساسيات جافاسكريبت</a> كما شرحناها في سلسلة المقالات السابقة.
		</p>
	</li>
	<li>
		<p>
			أساسيات البرمجة كائنية التوجه في جافا سكربت كما شرحناها في مقال <a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-r2305/" rel="">أساسيات العمل مع الكائنات في جافاسكربت</a>، ومقال الوراثة باستخدام الكائنات في جافاسكربت إضافة إلى <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%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-%D9%88%D8%AA%D8%AD%D9%82%D9%8A%D9%82%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2316/" rel="">مفاهيم أساسية في البرمجة كائنية التوجه</a>.
		</p>
	</li>
</ol>

<h2 id="-1">
	اﻷصناف والدوال البانية
</h2>

<p>
	يمكن التصريح عن صنف باستخدام الكلمة المحجوزة <code>new</code>، إليك كيفية تعريف الصنف <code>Person</code>الذي تعاملنا معه في مقال سابق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5942_12" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">constructor</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">this</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="pun">}</span><span class="pln">

  introduceSelf</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="typ">Hi</span><span class="pun">!</span><span class="pln"> I</span><span class="str">'</span><span class="pln">m $</span><span class="pun">{</span><span class="kwd">this</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="pun">}</span></pre>

<p>
	تُصرّح الشيفرة السابقة صنفًا يُدعى <code>person</code> له:
</p>

<ul>
	<li>
		الخاصية <code>name</code>.
	</li>
	<li>
		دالة بانية لها معامل وحيد <code>name</code> ويُستخدم لتهيئة قيمة الخاصية <code>name</code> للكائن الجديد.
	</li>
	<li>
		تابع <code>()introduceSelf</code> يمكنه اﻹشارة إلى خاصيات الكائن باستخدام التعليمة <code>this</code>.
	</li>
</ul>

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

<p>
	عّرفت الدالة البانية باستخدام الكلمة المحجوزة <code>constructor</code>، وكما هو الحال عند تعريف الدالة البانية خارج الصنف،سيكون لها المهام التالية:
</p>

<ul>
	<li>
		إنشاء كائن جديد.
	</li>
	<li>
		ربط التعليمة <code>this</code> بالكائن الجديد كي تتمكن من استخدام هذه التعليمة في اﻹشارة إلى الكائن ضمن شيفرتها.
	</li>
	<li>
		تنفيذ شيفرة الدالة البانية.
	</li>
	<li>
		إعادة الكائن الجديد.
	</li>
</ul>

<p>
	وبالعودة إلى شيفرة التصريح عن الكائن السابق، تستطيع إنشاء واستخدام نسخة جديدة من الكائن <code>Person</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5942_14" style=""><span class="kwd">const</span><span class="pln"> giles </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Person</span><span class="pun">(</span><span class="str">"Giles"</span><span class="pun">);</span><span class="pln">

giles</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Hi! I'm Giles</span></pre>

<p>
	لاحظ كيف نستدعي الدالة البانية باستخدام اسم الصنف، وهو <code>Person</code>في مثالنا.
</p>

<h2 id="-2">
	حذف الدالة البانية
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5942_16" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sleep</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">"zzzzzzz"</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">const</span><span class="pln"> spot </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Animal</span><span class="pun">();</span><span class="pln">

spot</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 'zzzzzzz'</span></pre>

<h2 id="inheritance">
	الوراثة Inheritance
</h2>

<p>
	تسمح الوراثة بإنشاء علاقة تسلسلية بين الكائنات، حيث يمكن للكائنات الفرعية أو الأبناء sub classes وراثة الخاصيات والتوابع من الكائنات الأساسية أو الآباء base classes، وفي نفس الوقت يمكنها تعديلها أو إضافة خصائص جديدة. لنتعرف على كيفية تحقيق مفهوم الوراثة في جافا سكريبت، لذا دعونا نستخدم الصنف<code>Person</code> السابق في تعريف كائن فرعي أو كائن ابن له باسم<code>professor</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5942_18" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Professor</span><span class="pln"> extends </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  teaches</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> teaches</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</span><span class="pun">(</span><span class="pln">name</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">teaches </span><span class="pun">=</span><span class="pln"> teaches</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  introduceSelf</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">
      </span><span class="pun">`</span><span class="typ">My</span><span class="pln"> name is $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">},</span><span class="pln"> and I will be your $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">teaches</span><span class="pun">}</span><span class="pln"> professor</span><span class="pun">.`,</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  grade</span><span class="pun">(</span><span class="pln">paper</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"> grade </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="pun">(</span><span class="lit">5</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="lit">1</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">grade</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نستخدم الكلمة المحجوزة <code>extends</code> للدالة إلى أن الصنف الجديد يرث صنفًا آخر. ويضيف الصنف <code>Professor</code> خاصية جديدة هي <code>teaches</code> لهذا نُصرّح عنها. وطالما أننا نريد تهيئة قيمة تلك الخاصية عندما ننشئ كائنًا جديدًا من الصنف <code>Professor</code>، لا بد من تعريف دالة بانية تأخذ معاملين هما <code>name</code> و <code>teaches</code>. وما تفعله الدالة البانية هنا، هو استدعاء الدالة البانية للصنف اﻷب باستخدام التابع <code>()super</code> ممررة له المعامل <code>name</code> وستتكفل الدالة البانية للصنف اﻷب بضبط قيمة الخاصية <code>name</code>. وبعدها تهيئ الدالة البانية للصنف <code>Professor</code> قيمة الخاصية <code>teaches</code>.
</p>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5942_20" style=""><span class="kwd">const</span><span class="pln"> walsh </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Professor</span><span class="pun">(</span><span class="str">"Walsh"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Psychology"</span><span class="pun">);</span><span class="pln">
walsh</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 'My name is Walsh, and I will be your Psychology professor'</span><span class="pln">

walsh</span><span class="pun">.</span><span class="pln">grade</span><span class="pun">(</span><span class="str">"my paper"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// some random grade</span></pre>

<h2 id="encapsulation">
	التغليف Encapsulation
</h2>

<p>
	لنرى أخيرًا كيف ننجز مفهوم التغليف في جافاسكريبت. فقد ناقشنا في مقال سابق كيف أردنا أن تكون الخاصية <code>year</code> للكائن <code>Student</code>خاصّة، كي نتمكن من تغيير شروط التسجيل في دروس الرماية دون اﻹخلال بالشيفرة التي تستخدم الكائن <code>Student</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5942_22" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Student</span><span class="pln"> extends </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">#</span><span class="pln">year</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> year</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</span><span class="pun">(</span><span class="pln">name</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.#</span><span class="pln">year </span><span class="pun">=</span><span class="pln"> year</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  introduceSelf</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="typ">Hi</span><span class="pun">!</span><span class="pln"> I</span><span class="str">'m ${this.name}, and I'</span><span class="pln">m in year $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.#</span><span class="pln">year</span><span class="pun">}.`);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  canStudyArchery</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">year </span><span class="pun">&gt;</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>
	وما فعلناه في التصريح السابق عن الصنف، أننا جعلنا الخاصية <code>year#</code> خاصّة بالصنف، وهكذا سنتمكن من بناء كائن <code>Student</code> يستخدم الخاصية <code>year#</code> داخليًا، وسيعطي المتصفح رسالة خطأ إن حاولت شيفرة خارج الكائن الوصول إليها.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5942_24" style=""><span class="kwd">const</span><span class="pln"> summers </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Student</span><span class="pun">(</span><span class="str">"Summers"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">

summers</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Hi! I'm Summers, and I'm in year 2.</span><span class="pln">
summers</span><span class="pun">.</span><span class="pln">canStudyArchery</span><span class="pun">();</span><span class="pln"> </span><span class="com">// true</span><span class="pln">

summers</span><span class="pun">.#</span><span class="pln">year</span><span class="pun">;</span><span class="pln"> </span><span class="com">// SyntaxError</span></pre>

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

<p>
	إذًا ينبغي أن يبدأ اسم الخاصيات الخاصة بالمحرف <code>#</code> ويجب أن يُصرّح عنها داخل الصنف.
</p>

<h3 id="privatemethods">
	التوابع الخاصة Private methods
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5942_26" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Example</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  somePublicMethod</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">somePrivateMethod</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="pun">#</span><span class="pln">somePrivateMethod</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 called me?"</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">const</span><span class="pln"> myExample </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Example</span><span class="pun">();</span><span class="pln">

myExample</span><span class="pun">.</span><span class="pln">somePublicMethod</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 'You called me?'</span><span class="pln">

myExample</span><span class="pun">.#</span><span class="pln">somePrivateMethod</span><span class="pun">();</span><span class="pln"> </span><span class="com">// SyntaxError</span></pre>

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

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

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

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%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-%D9%88%D8%AA%D8%AD%D9%82%D9%8A%D9%82%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2316/" 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>
	<li>
		<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%A8%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-oop/" rel="">لغة البرمجة بالكائنات Object-Oriented Programming</a>
	</li>
	<li>
		<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="">برمجة الكائنات Objects في جافاسكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%85%D8%AE%D8%AA%D8%B5%D8%B1-%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-oop-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D9%87%D8%A7-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1926/" rel="">مختصر البرمجة كائنية التوجه <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr> وتطبيقها في بايثون</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2317</guid><pubDate>Mon, 06 May 2024 12:04:01 +0000</pubDate></item><item><title>&#x645;&#x641;&#x627;&#x647;&#x64A;&#x645; &#x623;&#x633;&#x627;&#x633;&#x64A;&#x629; &#x641;&#x64A; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; &#x643;&#x627;&#x626;&#x646;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x648;&#x62C;&#x647; &#x648;&#x62A;&#x62D;&#x642;&#x64A;&#x642;&#x647;&#x627; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%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-%D9%88%D8%AA%D8%AD%D9%82%D9%8A%D9%82%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2316/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_05/1370103770_.png.600fd886f175ea57afad3a06cab2fe69.png" /></p>
<p>
	البرمجة كائنية التوجه Object-Oriented programming واختصارًا <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr> هي مصطلح برمجي أساسي في الكثير من لغات البرمجة مثل جافا و ++C. ونحاول في هذا المقال تزويدك بإحاطة شاملة عن أساسيات مفهوم البرمجة كائنية التوجه، ونشرح مفاهيمها اﻷساسية، ونوضح مفهوم اﻷصناف classes والنسخ instances والوراثة inheritance والتغليف encapsulation. ولن نخص في شرحنا لهذه المفاهيم لغة جافا سكريبت حاليًا، وستكون اﻷمثلة جميعها مكتوبة بلغة معممة (أو بالشيفرة الوهمية pseudo-code).
</p>

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

<p>
	بعد ذلك، سنوضح العلاقة بين الدوال البانية constructor وكائنات prototype في جافا سكريبت وبين مفاهيم البرمجة كائنية التوجه التي أشرنا إليها سابقًا، وأبرز الاختلافات بينها. وسنركز في مقالات لاحقة على بعض الميزات اﻹضافية في جافا سكريبت التي تساعد على تنفيذ برامج كائنية التوجه.
</p>

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

<ol>
	<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-%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/" 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-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-r2305/" rel="">أساسيات العمل مع الكائنات في جافا سكريبت</a>، ومقال <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-prototype-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2310/" rel=""> استخدام كائنات Prototype في جافا سكريبت</a>.
	</li>
</ol>

<h2>
	ما هي البرمجة كائنية التوجه
</h2>

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

<h2 id="classesinstances">
	اﻷصناف Classes والنُّسَخ Instances
</h2>

<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%A8%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-oop/" rel=""><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr></a>، ننشئ تعريفات عامة تمثّل أنواع الكائنات التي نريدها في المنظومة. فلو أدرنا مثلًا نمذجة مدرسة، قد نرغب بإنشاء كائنات تمثل المدرّسين، ويكون لهؤلاء المدرسين ميزات أو سمات مشتركة كأن يكون لهم أسماء ومواد يدرّسونها. وإضافة إلى ذلك، يمكن لأي مدرس تنفيذ أعمال محددة، مثل تصحيح اﻷوراق أو تقديم أنفسهم إلى الطلاب في بداية العام الدراسي مثلًا.
</p>

<p>
	لهذا يمكن أن يكون المدرّس ضنفًا في المنظومة باسم <code>Professor</code>، ويٌعرّف الصنف بداخله مجموعة من البيانات والتوابع التي يمتلكها كل مدرّس في المدرسة.
</p>

<p>
	على سبيل المثال يمكن أن يُعرّف الصنف <code>Professor</code> بالشيفرة الوهمية التالية:
</p>

<pre class="ipsCode">class Professor
    properties
        name
        teaches
    methods
        grade(paper)
        introduceSelf()
</pre>

<p>
	تُعرّف الشيفرة السابقة الصنف <code>Professor</code> كالتالي:
</p>

<ul>
	<li>
		خاصيتين أو سمتين تحملان بيانات المدرس وهما <code>name</code> التي تمثل اسم المدرس و <code>teaches</code> التي تمثل المواد التي يقوم بتدريسها.
	</li>
	<li>
		تابعين هما <code>()grade</code> لتصحيح ورقة، و <code>()introduceSelf</code> للتعريف عن أنفسهم.
	</li>
</ul>

<p>
	كما تلاحظ ليس للصنف وظيفة قائمة بحد ذاتها، بل هو أقرب إلى قالب ﻹنشاء كائنات objects من هذا النوع أو الصنف. فكل مدرّس ننشئه وفق القالب <code>Professor</code> يُدعى نسخة instance عن هذا القالب.
</p>

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

<p>
	تُكتب الدوال البانية عمومًا كجزء من تعريف الصنف، ولها عادة نفس اسم الصنف، لاحظ الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1607_11" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Professor</span><span class="pln">
    properties
        name
        teaches
    </span><span class="kwd">constructor</span><span class="pln">
        </span><span class="typ">Professor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> teaches</span><span class="pun">)</span><span class="pln">
    methods
        grade</span><span class="pun">(</span><span class="pln">paper</span><span class="pun">)</span><span class="pln">
        introduceSelf</span><span class="pun">()</span></pre>

<p>
	تأخذ الدالة البانية في الشيفرة السابقة معاملين أو وسيطين، لهذا بإمكاننا تهيئة الخاصيتين <code>name</code> و <code>teaches</code> عند إنشاء نسخة جديدة أو كائن عن صنف المدرّس. وطالما أن لدينا دالة بانية اﻵن، سنتمكن من إنشاء بعض المدرسين، وتستخدم بعض لغات البرمجة عادة الكلمة المحجوزة <code>new</code> للإشارة إلى استدعاء الدالة البانية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1607_13" style=""><span class="pln">walsh </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Professor</span><span class="pun">(</span><span class="str">"Ahmad"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Psychology"</span><span class="pun">);</span><span class="pln">
lillian </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Professor</span><span class="pun">(</span><span class="str">"Lyla"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Poetry"</span><span class="pun">);</span><span class="pln">

walsh</span><span class="pun">.</span><span class="pln">teaches</span><span class="pun">;</span><span class="pln"> </span><span class="com">// 'Psychology'</span><span class="pln">
walsh</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 'My name is Professor Ahmad and I will be your Psychology professor.'</span><span class="pln">

lillian</span><span class="pun">.</span><span class="pln">teaches</span><span class="pun">;</span><span class="pln"> </span><span class="com">// 'Poetry'</span><span class="pln">
lillian</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 'My name is Professor Lyla and I will be your Poetry professor.'</span></pre>

<p>
	تنشئ شيفرة جافا سكريبت السابقة كائنين، وكلاهما نسخة عن الصنف <code>Professor</code>.
</p>

<h2 id="inheritance">
	الوراثة Inheritance
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1607_15" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Student</span><span class="pln">
    properties
        name
        year
    </span><span class="kwd">constructor</span><span class="pln">
        </span><span class="typ">Student</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> year</span><span class="pun">)</span><span class="pln">
    methods
        introduceSelf</span><span class="pun">()</span></pre>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1607_17" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Person</span><span class="pln">
    properties
        name
    </span><span class="kwd">constructor</span><span class="pln">
        </span><span class="typ">Person</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln">
    methods
        introduceSelf</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Professor</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> extends </span><span class="typ">Person</span><span class="pln">
    properties
        teaches
    </span><span class="kwd">constructor</span><span class="pln">
        </span><span class="typ">Professor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> teaches</span><span class="pun">)</span><span class="pln">
    methods
        grade</span><span class="pun">(</span><span class="pln">paper</span><span class="pun">)</span><span class="pln">
        introduceSelf</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Student</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> extends </span><span class="typ">Person</span><span class="pln">
    properties
        year
    </span><span class="kwd">constructor</span><span class="pln">
        </span><span class="typ">Student</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> year</span><span class="pun">)</span><span class="pln">
    methods
        introduceSelf</span><span class="pun">()</span></pre>

<p>
	وهكذا يمكن القول أن الصنف <code>Person</code> هو صنف أعلى super class أو صنف أب parent class لكل من الصنف <code>Professor</code> والصنف <code>Student</code> اللذان يُدعيان في هذه الحالة بأصناف فرعية sub classes أو أصناف أبناء child class.
</p>

<p>
	ولاحظ كيف عُرِّف التابع <code>()introduceSelf</code> في جميع الأصناف الثلاث، والسبب هو اختلاف الطريقة التي يُقدّم فيها كل صنف نفسه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1607_21" style=""><span class="pln">ahmad </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Professor</span><span class="pun">(</span><span class="str">"Ahmad"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Psychology"</span><span class="pun">);</span><span class="pln">
ahmad</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 'My name is Professor Ahmad and I will be your Psychology professor.'</span><span class="pln">

summers </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Student</span><span class="pun">(</span><span class="str">"Summers"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
summers</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 'My name is Summers and I'm in the first year.'</span></pre>

<p>
	وباﻹمكان أيضًا كتابة تابع افتراضي <code>()introduceSelf</code> للتعريف عن أشخاص ليسوا طلابًا ولا مدرسين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1607_25" style=""><span class="pln">passam </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Person</span><span class="pun">(</span><span class="str">"Passam"</span><span class="pun">);</span><span class="pln">
passam</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 'My name is Passam.'</span></pre>

<p>
	تُدعى فكرة وجود تابع بنفس الاسم في عدة أصناف، لكنه ينفّذ وظيفة خاصة في كل صنف <strong>بتعدد الأشكال polymorphism</strong>، حيث يمكن تعريف تابع بنفس الاسم في الصنف الأب والابن وفي هذه الحالة يحل التابع المعرف في الصنف الابن محل التابع المعرف في الصنف الابن، ونقول في هذه الحالة أننا تجاوزنا overrides نسخة التابع الموجودة في الصنف اﻷب.
</p>

<h2 id="encapsulation">
	التغليف Encapsulation
</h2>

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

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

<p>
	فلو سمُح لطلاب السنة الثانية وما فوق دراسة الرماية، باﻹمكان تنفيذ اﻷمر بالاستفادة من الخاصية <code>year</code>، وستتمكن بقية الشيفرة من تحديد إمكانية تسجيل الطالب في صف الرماية أو لا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1607_27" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">student</span><span class="pun">.</span><span class="pln">year </span><span class="pun">&gt;</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">// allow the student into the class</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لكن المشكلة ستقع إذا غيرنا معيار السماح للطلاب بالتسجيل في درس الرماية، كأن يحتاج إلى موافقة ولي أمره، عندها علينا تغيير الشيفرة التي تتحقق من إمكانية تسجيل الطالب في كل مكان. لهذا من اﻷفضل إنشاء تابع <code>()canStudyArchery</code> في الكائنات <code>Student</code> لتنفيذ منطق العملية.
</p>

<ul>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1607_29" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Student</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> extends </span><span class="typ">Person</span><span class="pln">
    properties
       year
    </span><span class="kwd">constructor</span><span class="pln">
       </span><span class="typ">Student</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> year</span><span class="pun">)</span><span class="pln">
    methods
       introduceSelf</span><span class="pun">()</span><span class="pln">
       canStudyArchery</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">year </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">}</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1560_8" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">student</span><span class="pun">.</span><span class="pln">canStudyArchery</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// allow the student into the class</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	وبامكاننا في الكثير من لغات البرمجة كائنية التوجه منع بقية الشيفرة من الوصول إلى الحالة الداخلية للكائن بجعل خاصياتها <code>private</code>، وسينتج خطأ إن حاولت الشيفرة خارج الصنف الوصول إلى الخاصية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1607_33" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Student</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> extends </span><span class="typ">Person</span><span class="pln">
    properties
       </span><span class="kwd">private</span><span class="pln"> year
    </span><span class="kwd">constructor</span><span class="pln">
        </span><span class="typ">Student</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> year</span><span class="pun">)</span><span class="pln">
    methods
       introduceSelf</span><span class="pun">()</span><span class="pln">
       canStudyArchery</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">year </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

student </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Student</span><span class="pun">(</span><span class="str">'Wael'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
student</span><span class="pun">.</span><span class="pln">year </span><span class="com">// error: 'year' is a private property of Student</span></pre>

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

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

<p>
	ناقشنا حتى اللحظة في مقالنا الميزات اﻷساسية للبرمجة كائنية التوجه بالعموم والتي تعتمدها لغات برمجة عديدة مثل <a href="https://academy.hsoub.com/programming/cpp/" rel="">++C</a> و<a href="https://academy.hsoub.com/programming/java/" rel="">جافا</a>، وكنا قد ألقينا النظرة في مقالي <a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-r2305/" rel="">أساسيات الكائنات في جافا سكريبت</a> و<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-prototype-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2310/" rel="">كائنات prototype</a> عن مفهومي الدوال البانية والكائنات prototype. وترتبط هاتان الميزتان بالتأكيد مع ميزات البرمجة كائنية التوجه إلى حد ما.
</p>

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

<p>
	كما تبدي سلسلة prototype chain سلوكًا يشبه سلوك الوراثة، فلو كان لدينا كائن من الصنف <code>Student</code> يمتلك الكائن <code>Person</code> ككائن prototype، فسيرث الخاصية <code>name</code> والتابع <code>()introduceSelf</code>.
</p>

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

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

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

<p>
	فالكائنات في سلسلسة prototype chain هي أقرب إلى مفهوم التفويض delegation من مفهوم الوراثة. والتفويض هو نمط برمجي يعطي الكائن القدرة على تنفيذ مهمة ما توكل إليه بنفسه أو تفويض كائن آخر لتنفيذ هذه المهمة. وفي الكثير من اﻷحيان، نرى أن التفويض أكثر مرونة في ربط الكائنات مع بعضها مقارنة بالوراثة (لسبب مهم وهو إمكانية تغيير أو استبدال الكائن المفوَّض كليًا أثناء تنفيذ البرنامج).
</p>

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

<h2 id="-2">
	الخاتمة
</h2>

<p>
	تحدثنا في هذا المقال عن الميزات اﻷساسية للبرمجة كائنية التوجه <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr> وطريقة تحقيقها في جافا سكريبت، كما ألقينا نظرة سريعة على مواطن الشبه بين الدوال البانية وكائنات prototype في جافا سكريبت وبين مميزات <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%A8%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-oop/" rel="">البرمجة بالكائنات.</a>
</p>

<p>
	ترجمة-وبتصرف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_programming" rel="external nofollow">Object-Oriented programming</a>
</p>

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-prototype-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2310/" rel=""> استخدام كائنات Prototype في جافا سكريبت </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>
	<li>
		<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%A8%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-oop/" rel="">لغة البرمجة بالكائنات Object-Oriented Programming</a>
	</li>
	<li>
		<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="">برمجة الكائنات Objects في جافاسكريبت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2316</guid><pubDate>Fri, 03 May 2024 12:05:01 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x643;&#x627;&#x626;&#x646;&#x627;&#x62A; Prototype &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-prototype-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2310/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_04/1576466851_.png.11fbd4584c89449dce6c1c17d9df236d.png" /></p>
<p>
	يشير مصطلح prototype إلى اﻵلية التي ترث فيها الكائنات ميزات من بعضها في جافا سكريبت، ويختلف عملها عن الوراثة في غيرها من اللغات كائنية التوجه، وهذا ما سنشرحه في هذا المقال.
</p>

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

<ol>
	<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-%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/" 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-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-r2305/" rel="">أساسيات العمل مع الكائنات في جافا سكريبت</a>.
	</li>
</ol>

<h2 id="">
	سلسلة من اﻷنماط المجرّدة
</h2>

<p>
	حاول أن تنشئ في طرفية جافا سكريبت في متصفحك الكائن التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9448_6" style=""><span class="kwd">const</span><span class="pln"> myObject </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  city</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Madrid"</span><span class="pun">,</span><span class="pln">
  greet</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="typ">Greetings</span><span class="pln"> from $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">city</span><span class="pun">}`);</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

myObject</span><span class="pun">.</span><span class="pln">greet</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Greetings from Madrid</span></pre>

<p>
	يمتلك الكائن خاصية واحدة لتخزين البيانات هي <code>city</code> وتابعًا واحدًا هو <code>()greet</code>. فإن كتبت اسم الكائن تليه نقطة في الطرفية مثل <code>.myobject</code>، ستعرض الطرفية قائمة بجميع الخاصيات التي يمتلكها العنصر. وسترى إضافة إلى الخاصية <code>city</code> والتابع <code>()greet</code>، الكثير من الخاصيات اﻷخرى!
</p>

<pre class="ipsCode">__defineGetter__
__defineSetter__
__lookupGetter__
__lookupSetter__
__proto__
city
constructor
greet
hasOwnProperty
isPrototypeOf
propertyIsEnumerable
toLocaleString
toString
valueOf
</pre>

<p>
	جرّب الوصول إلى إحداها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9448_8" style=""><span class="pln">myObject</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">();</span><span class="pln"> </span><span class="com">// "[object Object]"</span></pre>

<p>
	لقد نجح اﻷمر (حتى لو لم يكن واضحًا لك بالضبط ما الذي يفعله التابع <a href="https://wiki.hsoub.com/JavaScript/Object/toString" rel="external">()toString </a>هنا). فما قصة هذه الخاصيات اﻹضافية، ومن أين أتت؟
</p>

<p>
	في الواقع يملك كل كائن في جافا سكريبت خاصية مضمنة تُدعى <a href="https://wiki.hsoub.com/JavaScript/Object/prototype" rel="external">prototype</a> وهي بحد ذاتها كائن أيضًا ويضم بدوره خاصية أو كائن مجرّد إن صح التعبير، مما يوّلد ما يُدعى سلسلة prototype chain. تنتهي السلسلة عند الوصول إلى كائن قيمة الخاصية prototype له تساوي <code>null</code>.
</p>

<p>
	<strong>ملاحظة</strong>:لا تُدعى الخاصية التي تشير إلى prototype بالاسم <code>prototype</code>، إذ ليس لها اسم معياري لكنها تُكتب بالممارسة العملية بالشكل <code>_proto_</code>. وتُعد الطريقة المعيارية للوصول إلى الخاصية prototype هي استخدام التابع <code>()Object.getPrototypeOf</code>.
</p>

<p>
	عندما تحاول الوصول إلى إحدى خاصيات كائن، ولم يُعثر على الخاصية في الكائن نفسه، يجري البحث عنها ضمن الكائن prototype، وإن لم يُعثر عليها يجري البحث مجددًا ضمن الكائن prototype للكائن prototype حتى نهاية السلسلة، فإن لم يجدها، سيُعيد القيمة <code>undefined</code>.
</p>

<p>
	فعندما تُنفّذ التعليمة <code>()myObject.toString</code>:
</p>

<ul>
	<li>
		يبحث المتصفح عن التابع <code>toString</code> ضمن الكائن <code>myObject</code>.
	</li>
	<li>
		إن لم يجده، سيبحث عنه في الكائن prototype للكائن <code>myObject</code>.
	</li>
	<li>
		يجده هناك ويستدعيه.
	</li>
</ul>

<p>
	لكن ما هو prototype للكائن <code>myObject</code>؟ لمعرفة ذلك، يمكننا استخدام الأمر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9448_10" style=""><span class="typ">Object</span><span class="pun">.</span><span class="pln">getPrototypeOf</span><span class="pun">(</span><span class="pln">myObject</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Object { }</span></pre>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="148737" href="https://academy.hsoub.com/uploads/monthly_2024_04/01_myobject-prototype-chain.PNG.344bcbc655330a57487a0c7073e09d41.PNG" rel=""><img alt="01 myobject prototype chain" class="ipsImage ipsImage_thumbnailed" data-fileid="148737" data-unique="7nbg306yn" src="https://academy.hsoub.com/uploads/monthly_2024_04/01_myobject-prototype-chain.thumb.PNG.06cf383f9a8998f93789ba4ba9fbed5a.PNG"> </a>
</p>

<p>
	لكن لا يمثل <code>Object.prototype</code> دائمًا prototype لكل كائن، جرّب ما يلي لترى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9448_12" style=""><span class="kwd">const</span><span class="pln"> myDate </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">();</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> object </span><span class="pun">=</span><span class="pln"> myDate</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">
  object </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getPrototypeOf</span><span class="pun">(</span><span class="pln">object</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">object</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">object</span><span class="pun">);</span><span class="pln">

</span><span class="com">// Date.prototype</span><span class="pln">
</span><span class="com">// Object { }</span><span class="pln">
</span><span class="com">// null</span></pre>

<p>
	تنشئ الشيفرة السابقة كائن من النوع <code><a href="https://wiki.hsoub.com/JavaScript/Date" rel="external">Date</a></code>، ثم تنتقل ضمن سلسلة كائنات prototype الخاصة به وتسجل أسماء هذه الكائنات. وتظهر أن النوع المجرد للكائن <code>myDate</code> هو <code>Date.prototype</code> وprototype الخاص بهذا اﻷخير هو <code>Object.prototype</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="148738" href="https://academy.hsoub.com/uploads/monthly_2024_04/02_mydate-prototype-chain.PNG.0e6481a4d8a9878f4206487ca92f8b76.PNG" rel=""><img alt="02 mydate prototype chain" class="ipsImage ipsImage_thumbnailed" data-fileid="148738" data-unique="w2665yu8y" src="https://academy.hsoub.com/uploads/monthly_2024_04/02_mydate-prototype-chain.thumb.PNG.7c8731df9ca43e35ac43a835ea4065f9.PNG"> </a>
</p>

<p>
	وعندما تستدعي توابع مثل <code>()mydate2.getMonth</code>، فأنت تستدعي في واقع اﻷمر توابع معرّفة ضمن النوع <code>Date.prototype</code>.
</p>

<h2 id="-1">
	إخفاء الخاصيات
</h2>

<p>
	ما الذي يحدث إن عرّفت خاصية في كائن وكانت هناك خاصية معرّفة بنفس الاسم ضمن الكائن prototype له؟ ألق نظرة على الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9448_14" style=""><span class="kwd">const</span><span class="pln"> myDate </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="lit">1995</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</span><span class="pun">,</span><span class="pln"> </span><span class="lit">17</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">myDate</span><span class="pun">.</span><span class="pln">getYear</span><span class="pun">());</span><span class="pln"> </span><span class="com">// 95</span><span class="pln">

myDate</span><span class="pun">.</span><span class="pln">getYear </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</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="str">"something else!"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

myDate</span><span class="pun">.</span><span class="pln">getYear</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 'something else!'</span></pre>

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

<h2 id="prototype-1">
	إعداد كائنات prototype
</h2>

<p>
	هناك طرق مختلفة ﻹعداد وضبط هذه الكائنات في جافا سكريبت، و سنناقش هنا طريقتان: الأولى باستخدام <code>()Object.create</code> والثانية استخدام الدوال البانية constructors.
</p>

<h3 id="objectcreate">
	استخدام التابع <code>()Object.create</code>
</h3>

<p>
	يُنشئ التابع <code>()Object.create</code> كائنًا جديدًا ويسمح لك بتخصيص كائن ليصبح prototype الجديد الخاص به، إليك مثالًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9448_16" style=""><span class="kwd">const</span><span class="pln"> personPrototype </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  greet</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">"hello!"</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">const</span><span class="pln"> carl </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">personPrototype</span><span class="pun">);</span><span class="pln">
carl</span><span class="pun">.</span><span class="pln">greet</span><span class="pun">();</span><span class="pln"> </span><span class="com">// hello!</span></pre>

<p>
	أنشأنا في الشيفرة السابقة كائنًا باسم <code>personPrototype</code>، يمتلك التابع <code>()greet</code>، ثم أنشأنا كائنًا جديدًا باستخدام التابع <code>()Object.create</code> وجعلنا <code>personPrototype</code> كائن prototype له. وبالتالي نستطيع اﻵن استدعاء التابع <code>()greet</code> من خلال الكائن الجديد، لأن كائن prototype قد زوّده به.
</p>

<h3 id="-2">
	استخدام الدالة البانية
</h3>

<p>
	تمتلك جميع الدوال في جافا سكريبت خاصية تًدعى <code>prototype</code>. وعندما تستدعي <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> على شكل دالة بانية، تُضبط تلك الخاصية لتكون prototype للكائن المبني حديثًا (داخل الخاصية التي تُدعى <code>_proto_</code> تقليديًا).
</p>

<p>
	لهذا، وعندما نضبط القيمة <code>prototype</code> للدالة البانية، نضمن أن الكائنات التي تُنشئها هذه الدالة تمتلك كائن prototype:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9448_19" style=""><span class="kwd">const</span><span class="pln"> personPrototype </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  greet</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">hello</span><span class="pun">,</span><span class="pln"> my name is $</span><span class="pun">{</span><span class="kwd">this</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="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Person</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">this</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="pun">}</span><span class="pln">

</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">assign</span><span class="pun">(</span><span class="typ">Person</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">,</span><span class="pln"> personPrototype</span><span class="pun">);</span><span class="pln">
</span><span class="com">// or</span><span class="pln">
</span><span class="com">// Person.prototype.greet = personPrototype.greet;</span></pre>

<p>
	لقد أنشأنا هنا:
</p>

<ul>
	<li>
		كائنًا بالاسم <code>personPrototype</code> يمتلك التابع <code>()greet</code>.
	</li>
	<li>
		دالة بانية <code>()Person</code> تهيئ اسم الشخص الذي نحييه.
	</li>
</ul>

<p>
	وضعنا بعد ذلك التوابع المعرّفة ضمن الكائن <code>personPrototype</code> ضمن الكائن prototype للدالة البانية باستخدام التابع <code>Object.assign</code>. وهكذا ستمتلك الكائنات المبنية باستخدام الدالة <code>()Person</code> prototype <code>Person.prototype</code> الذي يضم تلقائيًا التابع <code>greet</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9448_21" style=""><span class="kwd">const</span><span class="pln"> reuben </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Person</span><span class="pun">(</span><span class="str">"Reuben"</span><span class="pun">);</span><span class="pln">
reuben</span><span class="pun">.</span><span class="pln">greet</span><span class="pun">();</span><span class="pln"> </span><span class="com">// hello, my name is Reuben!</span></pre>

<p>
	يشرح هذا أيضًا ما قلناه سابقًا بأن الكائن prototype للكائن <code>myDate</code> هو <code>Date.prototype</code>، إذ يمثّل الخاصية للبانية <code>Date</code>.
</p>

<h3 id="-3">
	الخاصيات المملوكة Own properties
</h3>

<p>
	يمتلك الكائن الذي أنشأناه باستخدام البانية <code>()Person</code> خاصيتين:
</p>

<ul>
	<li>
		الخاصية <code>name</code> التي ضبطنا قيمتها باستخدام الدالة البانية، لهذا تظهر مباشرة ضم الكائن <code>Person</code>.
	</li>
	<li>
		التابع <code>()greet</code>الذي ضبُط من خلال الكائن prototype.
	</li>
</ul>

<p>
	من الشائع أن تشاهد هذا الأسلوب الذي تُعرّف فيه التوابع ضمن كائنات prototype، وتُعرّف فيه خاصيات البيانات ضمن الدوال البانية. ذلك أن التوابع تبقى نفسها عادة لجميع الكائنات التي ننشئها، لكننا غالبا ما نريد أن يأخذ كل كائن قيم مخصصة لخاصيات البيانات (كأن يكون لكل شخص اسم خاص).
</p>

<p>
	تُدعى الخاصيات التي تُعرّف مباشرة ضمن الكائن مثل الخاصية <code>name</code> بالخاصيات المملوكة Own Property، وبإمكانك التحقق من كون الخاصية مملوكة باستخدام التابع الساكن <code>()Object.hasOwn</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9448_23" style=""><span class="kwd">const</span><span class="pln"> irma </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Person</span><span class="pun">(</span><span class="str">"Irma"</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="typ">Object</span><span class="pun">.</span><span class="pln">hasOwn</span><span class="pun">(</span><span class="pln">irma</span><span class="pun">,</span><span class="pln"> </span><span class="str">"name"</span><span class="pun">));</span><span class="pln"> </span><span class="com">// true</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">hasOwn</span><span class="pun">(</span><span class="pln">irma</span><span class="pun">,</span><span class="pln"> </span><span class="str">"greet"</span><span class="pun">));</span><span class="pln"> </span><span class="com">// false</span></pre>

<p>
	<strong>ملاحظة</strong>: كما تستطيع استخدام التابع غير الساكن <code>()Object.hasOwnProperty</code> في هذه الحالة لكننا ننصح باستخدام التابع الساكن ما أمكن.
</p>

<h2 id="prototype-2">
	الكائنات prototype والوراثة
</h2>

<p>
	تُعد كائنات prototype ميزة قوية ومرنة في جافا سكريبت، تسمح لك بإعادة استخدام الشيفرة ودمج الكائنات. وهي بالتحديد تدعم نوعًا من <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%B1%D8%A7%D8%AB%D8%A9-%D8%A7%D9%84%D9%86%D9%85%D9%88%D8%B0%D8%AC%D9%8A%D8%A9-prototypal-inheritance-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA%D8%8C-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r887/" rel="">الوراثة inheritance</a>، والتي هي ميزة من ميزات البرمجة كائنية التوجه <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>. إذ تسمح الوراثة للمبرمج التعبير عن فكرة مفادها أن بعض الكائنات هي نسخ أكثر تخصيصًا من كائنات أخرى.
</p>

<p>
	فلو كنا نبني نموذجًا عن مدرسة، فقد ننشئ كائنات مثل مدرّس أو طالب وكلاهما أشخاص ويمتلكان بعض الميزات المتشابهة كاﻷسماء مثلًا، لكن قد يكون لكل منهما ميزات إضافية تميّزه عن اﻵخر (كأن يكون للمدرس موّاد يدرّسها)، وقد تنجز نفس الميزات بطريقة مختلفة لكل منهما. لهذا نقول في البرمجة كائنية التوجه <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr> بأن الطالب والمدرس كائنان يرثان من كائن آخر يُدعى شخص.
</p>

<p>
	أما في جافا سكريبت فيمكن للكائنين <code>Professor</code> و <code>Student</code> أن يمتلكا نفس الكائن المجرد <code>Person</code>، ويرثا الخاصيات التي يمتلكها كائن prototype كما يمكن أن نعرّف خاصيات وتوابع جديدة تناسب كل منهما.
</p>

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

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

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

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

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-r2305/" rel="">أساسيات العمل مع الكائنات في جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%88%D8%B1%D8%A7%D8%AB%D8%A9-%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-class-inheritance-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r902/" rel="">وراثة الأصناف (Class inheritance) في جافاسكربت</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/general/%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-oop/" rel="">لغة البرمجة بالكائنات Object-Oriented Programming</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2310</guid><pubDate>Sat, 27 Apr 2024 12:04:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x635;&#x641;&#x648;&#x641;&#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%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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_04/--.png.e7726dfbff5e2f023e93ee143f27a0df.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>
</ol>

<h2 id="-1">
	ما هي المصفوفات؟
</h2>

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

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

<p>
	وكما فعلنا في مقالات أخرى سنتدرب على أساسيات التعامل مع المصفوفات باستخدام طرفية جافا سكريبت في المتصفح والتي يمكنك الوصول لها من خلال النقر على مفاتيح (Ctrl + Shift+ K في فايرفكس).
</p>

<h2 id="-2">
	إنشاء المصفوفات
</h2>

<p>
	تتكون المصفوفة من قوسين مربعين وعناصر تفصل بينها فاصلة <code>,</code>.
</p>

<ol>
	<li>
		افترض أنك تريد تخزين لائحة التسوق التالية في مصفوفة، أنشأ هذه المصفوفة بنسخ ولصق الشيفرة التالية في الطرفية:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_13" style=""><span class="kwd">const</span><span class="pln"> shopping </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"bread"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"milk"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cheese"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"hummus"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"noodles"</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">shopping</span><span class="pun">);</span></pre>

<ol start="2">
	<li>
		إن كل عناصر المصفوفة السابقة هي عناصر نصية، لكن بإمكانك تخزين أنواع مختلفة من البيانات مثل الأعداد والسلاسل النصية والكائنات وحتى مصفوفات أخرى. كما يمكن استخدام أنواع مختلفة في المصفوفة نفسها، فلا ضرورة لإلزام أنفسنا بإنشاء مصفوفة لتخزين الأعداد وأخرى للنصوص. إليك مثالًا:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_15" style=""><span class="kwd">const</span><span class="pln"> sequence </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</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">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">13</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> random </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"tree"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">795</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="lit">0</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></pre>

<ol start="3">
	<li>
		جرب إنشاء بعض المصفوفات قبل المتابعة.
	</li>
</ol>

<h2 id="-3">
	إيجاد طول مصفوفة
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_17" style=""><span class="kwd">const</span><span class="pln"> shopping </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"bread"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"milk"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cheese"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"hummus"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"noodles"</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">shopping</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5</span></pre>

<h2 id="-4">
	الوصول إلى عناصر مصفوفة وتعديلها
</h2>

<ol>
	<li>
		تُرقم عناصر المصفوفة ابتداءً من الصفر ويُدعى هذا الرقم دليل العنصر item index. وهكذا سيكون دليل العنصر الأول هو 0 والثاني 1 وهكذا. وللوصول إلى عنصر معين في مصفوفة ضع اسم المصفوفة يليها قوسين مربعين ضمنهما دليل العنصر أي بنفس الطريقة التي تصل فيها إلى محرف في سلسلة نصية:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_19" style=""><span class="kwd">const</span><span class="pln"> shopping </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"bread"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"milk"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cheese"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"hummus"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"noodles"</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">shopping</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]);</span><span class="pln">
</span><span class="com">// returns "bread"</span></pre>

<ol start="2">
	<li>
		بالإمكان أيضًا تعديل عنصر في المصفوفة بإسناد قيمة جديدة إلى العنصر المطلوب:
	</li>
</ol>

<pre class="ipsCode">const shopping = ["bread", "milk", "cheese", "hummus", "noodles"];
shopping[0] = "tahini";
console.log(shopping);
// shopping will now return [ "tahini", "milk", "cheese", "hummus", "noodles" ]
</pre>

<p>
	<strong>ملاحظة</strong>: تذكر أن العد أو الفهرسة في جافا سكريبت تبدأ من 0 وليس من 1.
</p>

<ol start="3">
	<li>
		تُدعى المصفوفة ضمن مصفوفة بالمصفوفة متعددة الأبعاد، ويمكن الوصول إلى عنصر في مصفوفة موجودة ضمن مصفوفة أخرى بكتاب اسم المصفوفة الخارجية يليها زوجين من الأقواس المربعة يضم الأول دليل المصفوفة الداخلية ضمن المصفوفة الخارجية وفي الثاني دليل العنصر المطلوب في المصفوفة الداخلية. فلو أردت الوصول إلى أحد عناصر المصفوفة التي دليلها 2 (العنصر الثالث) ضمن المصفوفة <code>random</code> يمكنك إنجاز الأمر كالتالي:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_21" style=""><span class="kwd">const</span><span class="pln"> random </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"tree"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">795</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="lit">0</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">
random</span><span class="pun">[</span><span class="lit">2</span><span class="pun">][</span><span class="lit">2</span><span class="pun">];</span></pre>

<ol start="4">
	<li>
		جرّب أن تعدّل على عناصر المصفوفات التي أنشأتها قبل المتابعة.
	</li>
</ol>

<h2 id="-5">
	إيجاد دليل العناصر في مصفوفة
</h2>

<p>
	إن لم تكن تعرف دليل العنصر، استخدم التابع <code>()indexOf</code> الذي يأخذ العنصر وسيطًا له ويعيد دليله إن كان موجودًا أو 1- إن لم يجده.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_23" style=""><span class="kwd">const</span><span class="pln"> birds </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Parrot"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Falcon"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Owl"</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">birds</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"Owl"</span><span class="pun">));</span><span class="pln"> </span><span class="com">//  2</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">birds</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"Rabbit"</span><span class="pun">));</span><span class="pln"> </span><span class="com">// -1</span></pre>

<h2 id="-6">
	إضافة عنصر إلى مصفوفة
</h2>

<p>
	ﻹضافة عنصر أو أكثر إلى نهاية المصفوفة، نستخدم التابع <code>()push</code> وعليك حينها التأكد من إضافة عنصر أو آخر إلى نهاية المصفوفة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_27" style=""><span class="kwd">const</span><span class="pln"> cities </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Manchester"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Liverpool"</span><span class="pun">];</span><span class="pln">
cities</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"Cardiff"</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">cities</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [ "Manchester", "Liverpool", "Cardiff" ]</span><span class="pln">
cities</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"Bradford"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Brighton"</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">cities</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [ "Manchester", "Liverpool", "Cardiff", "Bradford", "Brighton" ]</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_29" style=""><span class="kwd">const</span><span class="pln"> cities </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Manchester"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Liverpool"</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> newLength </span><span class="pun">=</span><span class="pln"> cities</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"Bristol"</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">cities</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [ "Manchester", "Liverpool", "Bristol" ]</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">newLength</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3</span></pre>

<p>
	وﻹضافة عناصر إلى بداية مصفوفة، استخدم التايع <code>()unshift</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_31" style=""><span class="kwd">const</span><span class="pln"> cities </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Manchester"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Liverpool"</span><span class="pun">];</span><span class="pln">
cities</span><span class="pun">.</span><span class="pln">unshift</span><span class="pun">(</span><span class="str">"Edinburgh"</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">cities</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [ "Edinburgh", "Manchester", "Liverpool" ]</span></pre>

<h2 id="-7">
	إزالة عناصر من مصفوفة
</h2>

<p>
	ﻹزالة العنصر اﻷخير من مصفوفة، استخدم التابع <code>()pop</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_33" style=""><span class="kwd">const</span><span class="pln"> cities </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Manchester"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Liverpool"</span><span class="pun">];</span><span class="pln">
cities</span><span class="pun">.</span><span class="pln">pop</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">cities</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [ "Manchester" ]</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_35" style=""><span class="kwd">const</span><span class="pln"> cities </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Manchester"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Liverpool"</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> removedCity </span><span class="pun">=</span><span class="pln"> cities</span><span class="pun">.</span><span class="pln">pop</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">removedCity</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "Liverpool"</span></pre>

<p>
	وﻹزالة العنصر اﻷول من مصفوفة استخدم التابع <code>()shift</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_37" style=""><span class="kwd">const</span><span class="pln"> cities </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Manchester"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Liverpool"</span><span class="pun">];</span><span class="pln">
cities</span><span class="pun">.</span><span class="pln">shift</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">cities</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [ "Liverpool" ]</span></pre>

<p>
	وإن كنت تعلم دليل العنصر بإمكانك إزالته من المصفوفة باستخدام التابع <code>()splice</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_39" style=""><span class="kwd">const</span><span class="pln"> cities </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Manchester"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Liverpool"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Edinburgh"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Carlisle"</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> index </span><span class="pun">=</span><span class="pln"> cities</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"Liverpool"</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">index </span><span class="pun">!==</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  cities</span><span class="pun">.</span><span class="pln">splice</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">
</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">cities</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [ "Manchester", "Edinburgh", "Carlisle" ]</span></pre>

<p>
	يحدد الوسيط الأول للتابع <code>()splice</code> دليل العنصر الذي تبدأ عنده إزالة العناصر، ويحدد الوسيط الثاني عدد العناصر التي يجب إزالتها، وبالتالي بإمكانك استخدامه ﻹزالة عدة عناصر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_41" style=""><span class="kwd">const</span><span class="pln"> cities </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Manchester"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Liverpool"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Edinburgh"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Carlisle"</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> index </span><span class="pun">=</span><span class="pln"> cities</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"Liverpool"</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">index </span><span class="pun">!==</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  cities</span><span class="pun">.</span><span class="pln">splice</span><span class="pun">(</span><span class="pln">index</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</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">cities</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [ "Manchester", "Carlisle" ]</span></pre>

<h2 id="-8">
	الوصول إلى كل العناصر
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_43" style=""><span class="kwd">const</span><span class="pln"> birds </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Parrot"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Falcon"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Owl"</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"> bird </span><span class="kwd">of</span><span class="pln"> birds</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">bird</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_45" style=""><span class="kwd">function</span><span class="pln"> </span><span class="kwd">double</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"> </span><span class="lit">2</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"> numbers </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">5</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">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> doubled </span><span class="pun">=</span><span class="pln"> numbers</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="kwd">double</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">doubled</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [ 10, 4, 14, 12 ]</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_47" style=""><span class="kwd">function</span><span class="pln"> isLong</span><span class="pun">(</span><span class="pln">city</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"> city</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">8</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"> cities </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"London"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Liverpool"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Totnes"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Edinburgh"</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> longer </span><span class="pun">=</span><span class="pln"> cities</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">isLong</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">longer</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [ "Liverpool", "Edinburgh" ]</span></pre>

<p>
	وكذلك يستدعي التابع <code>()filter</code>دالة لاختبار كل عنصر من عناصر المصفوفة فإن أعادت القيمة <code>true</code> يُضاف العنصر إلى المصفوفة الجديدة ثم يعيد هذه المصفوفة في النهاية.
</p>

<h2 id="-9">
	التحويل بين المصفوفات والسلاسل النصية
</h2>

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

<ol>
	<li>
		أنشئ السلسلة النصية التالية في طرفية جافا سكربت <code>;"const data = "Manchester,London,Liverpool,Birmingham,Leeds,Carlisle</code>
	</li>
	<li>
		افصل السلسلة عند المحرف <code>,</code>:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_49" style=""><span class="pln">   </span><span class="kwd">const</span><span class="pln"> cities </span><span class="pun">=</span><span class="pln"> data</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">
   cities</span><span class="pun">;</span></pre>

<ol start="3">
	<li>
		حاول حساب طول المصفوفة الجديدة واستخلص بعض عناصرها:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_51" style=""><span class="pln">   cities</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
   cities</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln"> </span><span class="com">// the first item in the array</span><span class="pln">
   cities</span><span class="pun">[</span><span class="lit">1</span><span class="pun">];</span><span class="pln"> </span><span class="com">// the second item in the array</span><span class="pln">
   cities</span><span class="pun">[</span><span class="pln">cities</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="com">// the last item in the array</span></pre>

<ol start="4">
	<li>
		بإمكانك عكس العملية باستخدام التابع <code>()join</code>:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_53" style=""><span class="pln">   </span><span class="kwd">const</span><span class="pln"> commaSeparated </span><span class="pun">=</span><span class="pln"> cities</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="str">","</span><span class="pun">);</span><span class="pln">
   commaSeparated</span><span class="pun">;</span></pre>

<ol start="5">
	<li>
		كما يمكن تحويل المصفوفة إلى سلسلة نصية باستخدام التابع <code>()toString</code> الذي يعده البعض أبسط من <code>()join</code> لأنه يأخذ معاملًا وحيدًا، لكنه أكثر محدودية فلا يمكنه الفصل سوى عند المحرف <code>,</code> على عكس <code>()join</code> الذي يمكن أن تحدد فيه أكثر من محرف لفصل السلاسل.
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8726_55" style=""><span class="pln">   </span><span class="kwd">const</span><span class="pln"> dogNames </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Rocket"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Flash"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Bella"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Slugger"</span><span class="pun">];</span><span class="pln">
   dogNames</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Rocket,Flash,Bella,Slugger</span></pre>

<h2 id="-10">
	تطبيق عملي: طباعة قائمة منتجات
</h2>

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

<ol>
	<li>
		تحت التعليق <code>number 1//</code> ستجد عددًا من السلاسل النصية التي تضم كلا منها اسم المنتج وسعره ويفصل بينهما فاصلة. والمطلوب منك تحويلها إلى مصفوفة وتخزينها ضمن المتغيّر <code>products</code>
	</li>
	<li>
		أنشئ حلقة <code>for...of</code> تحت التعليق <code>number 2//</code> كي تمر على جميع عناصر المصفوفة السابقة.
	</li>
	<li>
		اكتب تحت التعليق <code>number 3//</code> شيفرة لفصل عناصر المصفوفة السابقة () إلى عنصرين يضم اﻷول الاسم والثاني السعر. إن لم تكن متأكدًا من طريقة تنفيذ اﻷمر راجع مقال [توابع جافا سكريبت اﻷصلية للتعامل مع النصوص]()، أو عد إلى فقرة التحويل بين المصفوفات والسلاسل النصية التي عرضناها قبل قليل.
	</li>
	<li>
		ويجب عليك أيضًا أن تحوّل السعر في السطر السابق من نص إلى عدد. يمكنك العودة إلى مقال <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2300/" rel="">التعامل مع النصوص في جافا سكريبت</a> كي تتذكر آلية تنفيذ اﻷمر.
	</li>
	<li>
		ستجد متغرًا باسم <code>total</code>وقد أسندت إليه القيمة 0. نطلب إليك أن تضيف سطرًا ضمن الحلقلة الموجودة أسفل التعليق <code>number 4//</code> ﻹضاف سعر العنصر الحالي إلى قيمة المتغير <code>total</code> عند كل تكرار للحلقة حتى نحصل في النهاية على إجمالي السعر أسفل الفاتورة، وقد تحتاج إلى استخدام عامل إسناد مناسب.
	</li>
	<li>
		غيّر السطر أسفل التعليق <code>number 5//</code> لتصبح قيمة المتغيّر مطابقة للسلسلة "العنصر الحالي — سعر العنصر الحالي$" مثل "Shoes — $23.99" عند كل تكرار كي تُطبع المعلومات الصحيحة لكل منتج ضمن الفاتورة. وتُنفّضذ العملية بضم بسيط لسلسلتين نصيتين.
	</li>
	<li>
		أضف القوس <code>{</code> أسفل التعليق <code>number 6//</code> ﻹنهاء حلقة <code>for...of</code>.
	</li>
</ol>

<p class="codepen" data-default-tab="result" data-height="750" data-slug-hash="RwOqbzb" data-user="HsoubAcademy" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
	<span>See the Pen <a href="https://codepen.io/HsoubAcademy/pen/RwOqbzb" rel="external nofollow"> js-array-1</a> by Hsoub Academy (<a href="https://codepen.io/HsoubAcademy" rel="external nofollow">@HsoubAcademy</a>) on <a href="https://codepen.io" rel="external nofollow">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

<h2 id="-11">
	تطبيق عملي: نتائج البحث الخمسة الأولى
</h2>

<p>
	يظهر استخدام مهم للتابعين <code>()push</code> و <code>()pop</code> عندما تريد أن تحدّث سجلًا لعناصر نشطة في تطبيق ويب، كأن يكون لديك تطبيق يعرض رسومًا متحركة ويضم عددًا كبيرًا من الكائنات مثل الخلفية وعناصر اخرى وتريد لسبب أو ﻵخر عرض 50 كائنًا فقط معًا. فعند إضافة عناصر جديدة لمصفوفة الكائنات تّحذف عناصر أقدم ليبقى عدد الكائنات المعروضة 50. في تطبيقنا هذا سنبسط اﻷمر أكثر، إذ سنفترض وجود محرك بحث وهمي يضم صندوق بحث، ومن المفترض عرض قائمة بآخر خمس عمليات بحث عند إدخال أي شيء في صندوق البحث. وعند تجاوز عمليات البحث 5 عمليات تُحذف العملية اﻷقدم وتضاف العملية الجديدة كي يبقى عدد عناصر القائمة 5. <strong>ملاحظة:</strong> قد تكون قادرًا في تطبيقات البحث الفعلية على النقر على زر ما لاستعادة جمع عمليات البحث التي جرت وطريقة لعرض كل النتائج. ﻹنجاز اﻷمر:
</p>

<ol>
	<li>
		أضف سطرًا تحت التعليق <code>number 1//</code> الذي يضيف عملية البحث المدخلة مؤخرًا إلى بداية المصفوفة، ويمكن الحصول على هذه القيمة من خلال اﻷمر <code>searchInput.vlue</code>.
	</li>
	<li>
		أضف سطرًا تحت التعليق <code>number 2//</code> كي يزيل العنصر الموجود في آخر المصفوفة حاليًا.
	</li>
</ol>

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

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

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

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

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2300/" rel="">توابع التعامل مع النصوص في جافا سكريبت</a>
	</li>
	<li>
		<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>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D9%88%D8%A7%D9%84%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-array-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1160/" rel="">البحث والترتيب في المصفوفات Array في جافا</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%88%D8%B8%D8%A7%D8%A6%D9%81-%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%D9%8A%D8%A8%D8%AA-%E2%80%93-%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-r558/" rel="">كيفية استخدام وظائف المصفوفات في الجافا سكريبت – توابع التعديل</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/javascript/" rel="">تعلم جافا سكريبت</a>
	</li>
</ul>

<p>
	 
</p>
]]></description><guid isPermaLink="false">2308</guid><pubDate>Fri, 26 Apr 2024 00:08:02 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x627;&#xFEF7;&#x62D;&#x62F;&#x627;&#x62B; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%EF%BB%B7%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%D9%8A%D8%A8%D8%AA-r2306/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_04/1296970442_.png.1f0dca4bce069b84b1aeed777331810d.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-%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/" rel="">أساسيات جافاسكريبت</a> كما شرحناها في سلسلة المقالات السابقة.
	</li>
</ol>

<h2 id="-1">
	ما هي اﻷحداث؟
</h2>

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

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

<p>
	إذًا هناك الكثير من اﻷحداث التي يمكن ترصدها.
</p>

<p>
	ولكي تستجيب لحدث ما، نربطه بما يُدعى معالج حدث event handler، وهو كتلة من الشيفرة (<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>) تُنفَّذ عندما يقع الحدث. وعندما تُعرف كتلة برمجية كهذه كي تعمل استجابة لوقوع حدث ما، نقول أننا سجلنا معالج حدث. وتجدر الملاحظة أن معالج الحدث يُسمى أحيانًا مترصد حدث event listener، وسنتستخدم المصطلحين معًا ويعملان معًا. فالمترصد هو من يكتشف وقوع الحدث والمعالج هو الشيفرة التي تُنفّذ استجابة له.
</p>

<p>
	<strong>ملاحظة</strong>: لا تُعد أحداث الويب جزءًا من بنية جافاسكريبت، بل كجزء من الواجهة البرمجية المدمجة مع المتصفح.
</p>

<h3 id="-2">
	مثال: التعامل مع حدث النقر على عنصر
</h3>

<p>
	لدينا في المثال التالي صفحة HTML تضم زرًا <code>&lt;button&gt;</code> واحدًا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3099_7" style=""><span class="tag">&lt;button&gt;</span><span class="pln">Change color</span><span class="tag">&lt;/button&gt;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_9" 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">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"> </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="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"> </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"> rndCol </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rgb</span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</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">backgroundColor </span><span class="pun">=</span><span class="pln"> rndCol</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="200" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/xxeyYyy?default-tab=result" style="width: 100%;" title="js-events-1">See the Pen js-events-1 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<h2 id="addeventlistener">
	استخدام التابع <code>()addEventListener</code>
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_11" 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">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"> </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="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"> </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"> rndCol </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rgb</span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</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">backgroundColor </span><span class="pun">=</span><span class="pln"> rndCol</span><span class="pun">;</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	سيحرّض المستخدم عندما ينقر على الزر <code>&lt;button&gt;</code> حدثًا، لذلك عرّفنا دالة <code>()addEventListener</code> نستدعيها عند وقوع الحدث ونمرر لها معاملين هما:
</p>

<ul>
	<li>
		القيمة النصية "click"ونحدد فيها أن الحدث الذي نترصده هو حدث النقر. ويمكن للأزرار أن تطلق العديد من اﻷحداث مثل <code>mouseover</code> عندما يحرّك المستخدم الفأرة فوق الزر أو <code>keydown</code> عندما يضغط على مفتاحًا ويكون تركيز الدخل على الزر.
	</li>
	<li>
		دالة نستدعيها عند وقوع الحدث، وفي حالتنا تولّد هذه الدالة لون RGB عشوائي وتضبط قيمة الخاصية <code>background-color</code> للعنصر <code>&lt;body&gt;</code> على قيمة اللون تلك.
	</li>
</ul>

<p>
	ولا بأس أن تفصل دالة الحدث باسم خاص بها كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_13" 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">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"> </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="pun">));</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> changeBackground</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"> rndCol </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rgb</span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</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">backgroundColor </span><span class="pun">=</span><span class="pln"> rndCol</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"> changeBackground</span><span class="pun">);</span></pre>

<h3 id="-3">
	ترصّد اﻷحداث
</h3>

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

<ul>
	<li>
		<code>focus</code> و <code>blur</code>: يتغير لون خلفية الصفحة عندما يتلقى الزر تركيز الدخل أو يفقد. حاول أن تنقل تركيز الدخل إلى الزر باستخدام المفتاح Tab ثم اضغط على المفتاح مجددًا ﻹبعاد تركيز الدخل. تُستخدم هذه اﻷحداث لعرض معلومات عن ملء نموذج بالبيانات عندما ينتقل التركيز إلى حقل نصي أو زر، أو لعرض رسالة خطأ عند ملئ أحد حقول النموذج بقيمة خاطئة.
	</li>
	<li>
		<code>dblclick</code>: يتغير اللون عندما تنقر الزر نقرًا مزدوجًا.
	</li>
	<li>
		<code>mouseover</code> أو <code>mouseout</code>: يتغير لون الخلفة عندما تمرر مؤشر الفأرة فوق الزر أو عندما يبتعد مؤشر الفأرة عن الزر.
	</li>
</ul>

<p>
	وبعض اﻷحداث مثل متاح تقريبًا لجميع العناصر، بينما يكون بعضها مخصصًا لحالات محددة. فالحدث <code>play</code> متاح مثلًا لبعض العناصر مثل العنصر <code>&lt;video</code>.
</p>

<h3 id="-4">
	إزالة مترصد حدث
</h3>

<p>
	عندما تضيف مترصد حدث باستخدام الدالة <code>()addEventListener</code>، بإمكانك إزالته باستخدام التابع <code>removeEventHandler</code>. ستزيل الشيفرة التالية معالج الحدث <code>()changeBackgroud</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_15" style=""><span class="pln">btn</span><span class="pun">.</span><span class="pln">removeEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> changeBackground</span><span class="pun">);</span></pre>

<p>
	كما يزال المعالج بتمرير إشارة إيقاف <code>AbortSignal</code> إلى الدالة <code>()addEventListener</code> ومن ثم استدعاء التابع <code>()abort</code> العائد للمتحكم controller الذي يمتلك إشارة اﻹيقاف لاحقًا.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_17" style=""><span class="kwd">const</span><span class="pln"> controller </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">AbortController</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"> rndCol </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rgb</span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</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">backgroundColor </span><span class="pun">=</span><span class="pln"> rndCol</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> signal</span><span class="pun">:</span><span class="pln"> controller</span><span class="pun">.</span><span class="pln">signal </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_3099_19" style=""><span class="pln">controller</span><span class="pun">.</span><span class="pln">abort</span><span class="pun">();</span><span class="pln"> </span><span class="com">// يزيل أي أو كل معالج حدث مرتبط بهذا المتحكم</span></pre>

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

<h3 id="-5">
	إضافة أكثر من مترصد لنفس الحدث
</h3>

<p>
	إن أردت استدعاء الدالة <code>()addEventListener</code> أكثر من مرة وتزويدها بأكثر من معالج حدث لنفس الحدث، يمكنك استخدام أكثر من معالج كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_21" style=""><span class="pln">myElement</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"> functionA</span><span class="pun">);</span><span class="pln">
myElement</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"> functionB</span><span class="pun">);</span></pre>

<p>
	وهكذا ستُنفَّذ كلا الدالتين في المعالجين السابقين عندما يُنقر الزر.
</p>

<p>
	عُد إلى موسوعة حسوب إن أردت الاطلاع على ميزات وخيرات أخرى مفيدة للدالة <code>()addEventListener</code>.
</p>

<h2 id="-6">
	آليات اخرى لاستخدام مترصد الحدث
</h2>

<p>
	ننصح دومًا باستخدام <code>()addEventListener</code> لتسجيل معالجات اﻷحداث، فهي الطريقة اﻷقوى وتتلائم جيدًا مع البرامج المعقدة. مع ذلك، هنالك طريقتان إضافيتين لتسجيل معالج الحدث قد تصادفهما وهما استعمال الخاصية الموافقة للحدث أو معالج الحدث السطري inline event handler.
</p>

<h3 id="-7">
	خاصيات معالج الحدث
</h3>

<p>
	للكائنات التي تطلق أحداثًا مثل اﻷزرار خاصيات تبدأ أسماؤها بالسابقة <code>on</code> يليها اسم معالج الحدث، مثل الخاصية <code>onclick</code>. تُدعى هذه الخاصيات بخاصيات معالج الحدث. ولكي تترصد حدثًا، أسند دالة معالج الحدث إلى هذه الخاصية كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_23" 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">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"> </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="pun">));</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

btn</span><span class="pun">.</span><span class="pln">onclick </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"> rndCol </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rgb</span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</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">backgroundColor </span><span class="pun">=</span><span class="pln"> rndCol</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_3099_25" 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">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"> </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="pun">));</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> bgChange</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"> rndCol </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rgb</span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</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">backgroundColor </span><span class="pun">=</span><span class="pln"> rndCol</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">onclick </span><span class="pun">=</span><span class="pln"> bgChange</span><span class="pun">;</span></pre>

<p>
	ولا يمكن بالطبع إسناد أكثر من معالج حدث إلى حدث ما باستخدام الخاصيات، إذ يمكنك مثلًا استدعاء الدالة <code>(click',handler')addEventListener</code> من قبل عنصر عدة مرات وبتمرير دوال معالجة مختلفة كوسيط ثانِ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_27" style=""><span class="pln">element</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"> function1</span><span class="pun">);</span><span class="pln">
element</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"> function2</span><span class="pun">);</span></pre>

<p>
	لكن ذلك مستحيل التنفيذ باستخدام الخاصيات لأن الإسناد الثاني سيلغي اﻷول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_29" style=""><span class="pln">element</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> function1</span><span class="pun">;</span><span class="pln">
element</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> function2</span><span class="pun">;</span></pre>

<h3 id="-8">
	معالجات الأحداث السطرية
</h3>

<p>
	لا تستخدم هذه الطريقة، لكنك قد تصادفها:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3099_31" 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">bgChange</span><span class="pun">()</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">Press me</span><span class="tag">&lt;/button&gt;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_33" style=""><span class="kwd">function</span><span class="pln"> bgChange</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"> rndCol </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rgb</span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</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">backgroundColor </span><span class="pun">=</span><span class="pln"> rndCol</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ظهرت هذه الطريقة في مراحل مبكرة وتضمنت استخدام سمات HTML التي تحدد معالج الحدث (المعالجات السطرية inline event handler) كما تعرضه الشيفرة السابقة. وتحمل هذه السمة حرفيًا شيفرة جافاسكريبت التي تريد تنفيذها عند وقوع الحدث. نستدعي في المثال السابق دالة معرّفة ضمن العنصر <code>&lt;script&gt;</code> في نفس الصفحة، كما يمكنك إدراج شيفرة جافاسكريبت مباشرة ضمن السمة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_35" style=""><span class="pun">&lt;</span><span class="pln">button onclick</span><span class="pun">=</span><span class="str">"alert('Hello, this is my old-fashioned event handler!');"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="typ">Press</span><span class="pln"> me
</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

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

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_37" 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"> bgChange</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<h2 id="-9">
	كائنات الحدث
</h2>

<p>
	قد تجد ضمن دالة الحث معاملات خاصة تحمل أسماء مثل <code>event</code> أو <code>evt</code> أو <code>e</code>، تُدعى هذه المعاملات كائنات حدث event object، وتمرر تلقائيًا إلى المعالجات لتزويدها بميزات ومعلومات إضافية. لنُعِد على سبيل المثال كتابة مثال اﻷلون العشوائية السابق مع بعض الاختلاف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_39" 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">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"> </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="pun">));</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> bgChange</span><span class="pun">(</span><span class="pln">e</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"> rndCol </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rgb</span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)})`;</span><span class="pln">
  e</span><span class="pun">.</span><span class="pln">target</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"> rndCol</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">e</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"> bgChange</span><span class="pun">);</span></pre>

<p>
	<strong>ملاحظة</strong>: يمكنك إيجاد <a href="https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/events/random-color-eventobject.html" rel="external nofollow">الشيفرة الكاملة</a> لهذا المثال على جت-هب (جرّب الشيفرة <a href="https://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-eventobject.html" rel="external nofollow">مباشرة</a> أيضًا).
</p>

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

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

<h3 id="-10">
	خاصيات إضافية لكائن اﻷحداث
</h3>

<p>
	لبعض كائنات الأحداث خاصيات إضافية تتعلق بالطبيعة الخاصة لكل حدث. إذ يقع الحدث <code>keydown</code> مثلًا عندما يضغط المستخدم على مفتاح، لهذا يضم كائن اﻷحداث الموافق له <code>keyboardEvent</code> الخاصية <code>key</code> التي تعطيك الزر الذي ضغطه المستخدم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_41" style=""><span class="kwd">const</span><span class="pln"> textBox </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">"#textBox"</span><span class="pun">);</span><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><span class="pln">
textBox</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"keydown"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</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">
  output</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">You</span><span class="pln"> pressed </span><span class="str">"${event.key}"</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="200" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/NWmOyeb?default-tab=result" style="width: 100%;" title="js-events-2">See the Pen js-events-2 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<h2 id="-11">
	إيقاف السلوك الافتراضي
</h2>

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

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

<p>
	لنلق نظرة على المثال التالي:
</p>

<p>
	إليك أولًا ملف htmL بسيط تحتاجه لإدخال الاسم اﻷول واﻷخير للمستخدم:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3099_43" style=""><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;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"fname"</span><span class="tag">&gt;</span><span class="pln">First 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">"fname"</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;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&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">"lname"</span><span class="tag">&gt;</span><span class="pln">Last 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">"lname"</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;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&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">"submit"</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="tag">/&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;p&gt;&lt;/p&gt;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_45" style=""><span class="kwd">const</span><span class="pln"> form </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">"form"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> fname </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">"fname"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> lname </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">"lname"</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">

form</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"submit"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</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">fname</span><span class="pun">.</span><span class="pln">value </span><span class="pun">===</span><span class="pln"> </span><span class="str">""</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> lname</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"> </span><span class="pun">{</span><span class="pln">
    e</span><span class="pun">.</span><span class="pln">preventDefault</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 need to fill in both names!"</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="200" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/QWPZQYp?default-tab=result" style="width: 100%;" title="js-events-3">See the Pen js-events-3 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<p>
	<strong>ملاحظة</strong>: يمكنك إيجاد <a href="https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/events/preventdefault-validation.html" rel="external nofollow">الشيفرة الكاملة</a> لهذا المثال على جت-هب (جرّب الشيفرة <a href="https://mdn.github.io/learning-area/javascript/building-blocks/events/preventdefault-validation.html" rel="external nofollow">مباشرة</a> أيضًا).
</p>

<h2 id="-12">
	رفع اﻷحداث
</h2>

<p>
	يُقصد برفع اﻷحداث bubbling كيفية تعامل المتصفح مع اﻷحداث المستهدفة لعناصر متداخلة.
</p>

<h3 id="-13">
	إعداد مترصد لعنصر أب
</h3>

<p>
	تأمل صفحة ويب لها الهيكلية التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3099_47" style=""><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;button&gt;</span><span class="pln">Click me!</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;pre</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"output"</span><span class="tag">&gt;&lt;/pre&gt;</span></pre>

<p>
	إن الزر هنا داخل العنصر <code>&lt;div&gt;</code> الذي يمثل العنصر اﻷب له. ما الذي سيحدث إن أضفنا معالج حدث نقر إلى العنصر اﻷب ثم نقرنا الزر؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_49" style=""><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><span class="pln">
</span><span class="kwd">function</span><span class="pln"> handleClick</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  output</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">You</span><span class="pln"> clicked on a $</span><span class="pun">{</span><span class="pln">e</span><span class="pun">.</span><span class="pln">currentTarget</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">}</span><span class="pln"> element\n</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"> container </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">"#container"</span><span class="pun">);</span><span class="pln">
container</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"> handleClick</span><span class="pun">);</span></pre>

<p>
	لاحظ كيف يطلق العنصر اﻷب الحدث عندما ينقر المستخدم الزر:
</p>

<pre class="ipsCode">You clicked on a DIV element
</pre>

<p>
	إن اﻷمر منطقي، فالزر ضمن العنصر <code>&lt;div&gt;</code> وعندما تنقر هذا العنصر فانت تنقر على الزر ضمنًا.
</p>

<h3 id="-14">
	مثال عن رفع الحدث
</h3>

<p>
	ما الذي قد يحدث إن أضفنا مترصد الحدث إلى الزر وليس إلى العنصر اﻷب؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_52" style=""><span class="pun">&lt;</span><span class="pln">body</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div id</span><span class="pun">=</span><span class="str">"container"</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="typ">Click</span><span class="pln"> me</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><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">pre id</span><span class="pun">=</span><span class="str">"output"</span><span class="pun">&gt;&lt;/</span><span class="pln">pre</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">body</span><span class="pun">&gt;</span></pre>

<p>
	لنجرّب إضافة حدث نقر إلى الزر (الموجود ضمن <code>&lt;div&gt;</code> وكلاهما ضمن العنصر <code>&lt;body&gt;</code><span class="ipsEmoji">?</span>
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_54" style=""><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><span class="pln">
</span><span class="kwd">function</span><span class="pln"> handleClick</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  output</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">You</span><span class="pln"> clicked on a $</span><span class="pun">{</span><span class="pln">e</span><span class="pun">.</span><span class="pln">currentTarget</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">}</span><span class="pln"> element\n</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"> container </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">"#container"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> button </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">

document</span><span class="pun">.</span><span class="pln">body</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"> handleClick</span><span class="pun">);</span><span class="pln">
container</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"> handleClick</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"> handleClick</span><span class="pun">);</span></pre>

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

<p>
	سترى أن العناصر الثلاث جميعها ستطلق الحدث عندما ينقر المستخدم على الزر:
</p>

<pre class="ipsCode">You clicked on a BUTTON element
You clicked on a DIV element
You clicked on a BODY element
</pre>

<p>
	في هذه الحالة:
</p>

<ul>
	<li>
		يُطلق حدث النقر على الزر أولًا.
	</li>
	<li>
		يليه حدث النقر على العنصر اﻷب (العنصر <code>&lt;div&gt;</code>).
	</li>
	<li>
		يليه حدث النقر على العنصر اﻷب للعنصر <code>&lt;div&gt;</code> (العنصر <code>&lt;div&gt;</code>).
	</li>
</ul>

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

<h3 id="-15">
	مثال عن مشغّل فيديو
</h3>

<p>
	تضم صفحتنا في هذا المثال فيديو أُخفي عمدًا وزر عنوانه "Display vedio". ونريد ان نظهر السلوك التفاعلي التالي:
</p>

<ul>
	<li>
		عندما ينقر المستخدم على الزر، يُعرض الصندوق الذي يضم الفيديو، لكنه لا يُشغّل المقطع.
	</li>
	<li>
		عندما ينقر المستخدم على الفيديو، يبدأ العرض.
	</li>
	<li>
		عندما ينقر المستخدم في أي مكان في الصندوق خارج الفيديو يختفي الصندوق.
	</li>
</ul>

<p>
	إليك شيفرة HTML:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3099_56" style=""><span class="tag">&lt;button&gt;</span><span class="pln">Display video</span><span class="tag">&lt;/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">"hidden"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;video&gt;</span><span class="pln">
    </span><span class="tag">&lt;source</span><span class="pln">
      </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm"</span><span class="pln">
      </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"video/webm"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;p&gt;</span><span class="pln">
      Your browser doesn't support HTML video. Here is a
      </span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"rabbit320.mp4"</span><span class="tag">&gt;</span><span class="pln">link to the video</span><span class="tag">&lt;/a&gt;</span><span class="pln"> instead.
    </span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;/video&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	تتضمن الشيفرة:
</p>

<ul>
	<li>
		زر <code>&lt;button&gt;</code>.
	</li>
	<li>
		عنصر حاوية <code>&lt;div&gt;</code> له السمة <code>"class="hidden</code>.
	</li>
	<li>
		عنصر <code>&lt;video&gt;</code> ضمن العنصر <code>&lt;div&gt;</code>.
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_58" 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"> box </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">"div"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> video </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">"video"</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"> box</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">(</span><span class="str">"hidden"</span><span class="pun">));</span><span class="pln">
video</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"> video</span><span class="pun">.</span><span class="pln">play</span><span class="pun">());</span><span class="pln">
box</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"> box</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="str">"hidden"</span><span class="pun">));</span></pre>

<p>
	تضيف الشيفرة ثلاثة مترصدين للحدث <code>'click'</code>:
</p>

<ul>
	<li>
		اﻷول للزر <code>&lt;button&gt;</code> الذي يعرض الحاوية التي تضم الفيديو.
	</li>
	<li>
		والثاني للفيديو <code>&lt;video&gt;</code> لكي يُشغّله.
	</li>
	<li>
		والثالث للحاوية <code>&lt;div&gt;</code> لكي يخفي الفيديو.
	</li>
</ul>

<p>
	راقب كيف يجري اﻷمر:
</p>

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

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

<h3 id="stoppropogation">
	إصلاح المشكلة باستخدام الدالة <code>()stoppropogation</code>
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_60" 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"> box </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">"div"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> video </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">"video"</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"> box</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">(</span><span class="str">"hidden"</span><span class="pun">));</span><span class="pln">

video</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">event</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">
  event</span><span class="pun">.</span><span class="pln">stopPropagation</span><span class="pun">();</span><span class="pln">
  video</span><span class="pun">.</span><span class="pln">play</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">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"> box</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="str">"hidden"</span><span class="pun">));</span></pre>

<p>
	كل ما فعلناه هنا هو استدعاء الدالة <code>()stopPropogation</code> العائدة لكائن اﻷحداث داخل معالج الحدث الذي يتعامل مع الحدث <code>'click'</code> الخاص بالعنصر <code>&lt;video&gt;</code>. سيمنع ذلك الحدث من الارتفاع إلى الصندوق. جرّب أن تنقر على الزر ثم على الفيديو:
</p>

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

<h3 id="-16">
	التقاط الحدث
</h3>

<p>
	إن الشكل اﻵخر لانتقال اﻷحداث هو التقاط الحدث event capture. واﻷمر مشابه لرفع الحدث لكن بترتيب معكوس. فبدلًا من اطلاق الحدث أولًا من قبل العنصر اﻷدنى في التسلسل الهرمي ثم ينتقل الحدث صعودًا إلى العنصر اﻷعلى مستوىً، يحدث العكس ويطلق الحدث العنصر اﻷعلى مستوى ويهبط وصولًا إلى العنصر اﻷدنى مستوىً.
</p>

<p>
	هذا الخيار معطّل افتراضيًا وعليك أن تمرر الخيار <code>capture</code> إلى الدالة <code>()addEventListener</code>.
</p>

<p>
	يعرض المثال التالي نفس المثال السابق عن رفع اﻷحداث لكن سنستخدم فيه الخيار <code>capture</code>. إليك شيفرة HTML:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3099_62" style=""><span class="tag">&lt;body&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;button&gt;</span><span class="pln">Click me!</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;pre</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"output"</span><span class="tag">&gt;&lt;/pre&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3099_64" style=""><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><span class="pln">
</span><span class="kwd">function</span><span class="pln"> handleClick</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  output</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">You</span><span class="pln"> clicked on a $</span><span class="pun">{</span><span class="pln">e</span><span class="pun">.</span><span class="pln">currentTarget</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">}</span><span class="pln"> element\n</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"> container </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">"#container"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> button </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">

document</span><span class="pun">.</span><span class="pln">body</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"> handleClick</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> capture</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">
container</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"> handleClick</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> capture</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">
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"> handleClick</span><span class="pun">);</span></pre>

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

<p>
	تُعكس في هذه الحالة الرسائل التي تُعرض عند تنفيذ الشيفرة، حيث يطلق العنصر <code>&lt;body&gt;</code> الحدث أولًا يليه العنصر <code>&lt;div&gt;</code> من ثم الزر <code>&lt;button&gt;</code>:
</p>

<pre class="ipsCode">You clicked on a BODY element
You clicked on a DIV element
You clicked on a BUTTON element
</pre>

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

<h2 id="-17">
	تفويض اﻷحداث
</h2>

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

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

<p>
	إليك شيفرة HTML:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3099_66" style=""><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</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&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">"tile"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	إليك شيفرة CSS بسيطة لتحديد موضع وأبعاد اﻷقسام:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_3099_68" style=""><span class="pun">.</span><span class="pln">tile </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">100px</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">25%</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">float</span><span class="pun">:</span><span class="pln"> left</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_3099_70" style=""><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"> bgChange</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"> rndCol </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rgb</span><span class="pun">(</span><span class="pln">$</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">random</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)})`;</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> rndCol</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"> container </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">"#container"</span><span class="pun">);</span><span class="pln">

container</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">event</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">
  event</span><span class="pun">.</span><span class="pln">target</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"> bgChange</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="500" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/PogyQrN?default-tab=result" style="width: 100%;" title="js-events-8">See the Pen js-events-8 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<p>
	<strong>ملاحظة</strong>: نستخدم في هذا المثال الخاصية <code>event.target</code> للحصول على العنصر الذي كان هدفًا للحدث. لكن إذا أردنا الوصول إلى العنصر الذي يعالج الحدث (وهو في حالتنا العنصر اﻷدنى مستوى) يمكن استخدام الخاصية <code>event.currentTarget</code>.
</p>

<p>
	<strong>ملاحظة</strong>: يمكنك إيجاد <a href="https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/events/useful-eventtarget.html" rel="external nofollow">الشيفرة الكاملة</a> لهذا المثال على جت-هب (جرّب الشيفرة <a href="https://mdn.github.io/learning-area/javascript/building-blocks/events/useful-eventtarget.html" rel="external nofollow">مباشرة</a> أيضًا).
</p>

<h2 id="-18">
	اﻷحداث ليست فقط لصفحات الويب
</h2>

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

<p>
	ونجد مثلًا بيئة <a href="https://wiki.hsoub.com/Node.js" rel="external">Node.js</a> وهي بيئة تنفيذية شعبية لجافاسكريبت تساعد المطوّرين على بناء تطبيقات للشبكات وتطبيقات الخادم، أن <a href="https://nodejs.org/api/events.html" rel="external nofollow">نموذجها الخاص بالأحداث</a> يعتمد على مترصدي اﻷحداث listeners لترقب وقوع الحدث ومصدري اﻷحداث emitters لبث اﻷحداث دوريًا. قد لا يبدو اﻷمر مختلفًا جدًا، لكن الشيفرة مختلفة تمامًا. إذ تُستخدم دوال مثل <code>()on</code> لتسجيل مترصد حدث، و <code>()once</code> لتسجيل مترصد أحداث مرة واحدة ثم إلغاء تسجيله بعد تنفيذه مباشرة. يمكنك الاطلاع على <a href="https://nodejs.org/api/http.html#event-connect" rel="external nofollow">توثيق أحداث الاتصال وفق بروتوكول HTTP</a> لأمثلة أوضح.
</p>

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

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

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

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

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

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

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

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D8%B9%D9%8A%D8%AF-%D9%82%D9%8A%D9%85%D9%8B%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2298/" rel="">الدوال التي تعيد قيمًا في جافا سكريبت</a>
	</li>
	<li>
		<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>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%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%D9%8A%D8%A8%D8%AA-r1354/" rel="">معالجة الأحداث في جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D8%A7%D9%84%D9%85%D8%AA%D8%B9%D9%84%D9%82%D8%A9-%D8%A8%D8%AF%D9%88%D8%B1%D8%A9-%D8%AD%D9%8A%D8%A7%D8%A9-%D8%B5%D9%81%D8%AD%D8%A9-html-%D9%88%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%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-r1236/" rel="">الأحداث المتعلقة بدورة حياة صفحة HTML وكيفية التحكم بها عبر جافاسكربت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2306</guid><pubDate>Sun, 21 Apr 2024 12:05:02 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x639;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x643;&#x627;&#x626;&#x646;&#x627;&#x62A; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%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-r2305/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_04/876394339_.png.50e9f21fef17999556e5c9768287ea70.png" /></p>
<p>
	نلقي نظرة في هذا المقال على الصياغة اﻷساسية لكائن جافا سكريبت كما نستذكر بعض الميزات التي ناقشناها سابقًا لنشدد على حقيقة أن العديد من الميزات التي اطلعنا عليها وتعاملنا معها في لغة جافا سكريبت هي في الواقع كائنات، ابتداءً من المميزات البنيوية للغة مثل المصفوفات إلى الواجهات البرمجية للمتصفحات APIs المبنية على أساس جافا سكريبت.
</p>

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

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

<ol>
	<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-%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/" rel="">أساسيات جافا سكريبت</a>
	</li>
</ol>

<h2 id="-1">
	أساسيات الكائنات
</h2>

<p>
	الكائن object هو مجموعة مترابطة من البيانات أو الوظائف، فهو يتألف عادة من من عدة متغيرات ودوال (تُدعى المتغيرات ضمن الكائن خاصيات properties والدوال methods). وحتى نستوعب مفهوم الكائنات سنعمل على المثال التالي. أنشئ أولًا نسخة من الملف <a href="https://github.com/mdn/learning-area/blob/main/javascript/oojs/introduction/oojs.html" rel="external nofollow">oojs.html</a> على حاسوبك. ويتضمن هذا الملف العنصر <code>&lt;script&gt;</code> الذي سنكتب ضمنه الشيفرة. سنستخدم هذه الصفحة كأساس لاستكشاف الصياغة اﻷساسية للكائن في جافا سكريبت. وعليك أن تفتح طرفية جافا سكريبت الخاصة بأدوات مطوري ويب وتجعلها جاهزة لكتابة التعليمات.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_7" style=""><span class="kwd">const</span><span class="pln"> person </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span></pre>

<p>
	افتح اﻵن طرفية جافا سكريبت ثم اكتب <code>person</code> ضمنها ثم اضغط المفتاح Enter. من المفترض أن تحصل على نتيجة مشابهة للتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_9" style=""><span class="pun">[</span><span class="pln">object </span><span class="typ">Object</span><span class="pun">]</span><span class="pln">
</span><span class="typ">Object</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_4490_11" style=""><span class="kwd">const</span><span class="pln"> person </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><span class="str">"Bob"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Smith"</span><span class="pun">],</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">32</span><span class="pun">,</span><span class="pln">
  bio</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</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">$</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">[</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">name</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]}</span><span class="pln"> is $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> years old</span><span class="pun">.`);</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  introduceSelf</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</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="typ">Hi</span><span class="pun">!</span><span class="pln"> I</span><span class="str">'</span><span class="pln">m $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</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>
	جرّب إدخال بعض التعليمات كما يلي في طرفية جافا سكريبت وذلك بعد حفظ التغييرات وإعادة تحميل الصفحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_13" style=""><span class="pln">person</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">name</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">age</span><span class="pun">;</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">bio</span><span class="pun">();</span><span class="pln">
</span><span class="com">// "Bob Smith is 32 years old."</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln">
</span><span class="com">// "Hi! I'm Bob."</span></pre>

<p>
	يضم الكائن بعض البيانات اﻵن كما يحتوي على بعض الوظائف التي يمكن الوصول إليها من خلال صياغة بسيطة واضحة.
</p>

<p>
	ما الذي يحدث فعلًا في مثالنا؟ لقد أنشأنا كائنًا مكوّنًا من عدة أعضاء members لكل منها اسم ( مثال <code>name</code> و <code>age</code>) وقيمًا مثل <code>['Bob, 'Smiths]</code> و <code>32</code>. يفصل بين كل زوج (اسم/قيمة) فاصلة <code>,</code>، وبين كل اسم وقيمة نجد نقطتين متعامدتين <code>:</code>. وتتبع صياغة الكائن الشكل التالي دائمًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_15" style=""><span class="kwd">const</span><span class="pln"> objectName </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  member1Name</span><span class="pun">:</span><span class="pln"> member1Value</span><span class="pun">,</span><span class="pln">
  member2Name</span><span class="pun">:</span><span class="pln"> member2Value</span><span class="pun">,</span><span class="pln">
  member3Name</span><span class="pun">:</span><span class="pln"> member3Value</span><span class="pun">,</span><span class="pln">
</span><span class="pun">};</span></pre>

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

<p>
	وعندما يكون عضو الكائن دالة، باﻹمكان استخدام صياغة أبسط من <code>bio:function</code>، ويكفي أن نكتب <code>()bio</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_17" style=""><span class="kwd">const</span><span class="pln"> person </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><span class="str">"Bob"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Smith"</span><span class="pun">],</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">32</span><span class="pun">,</span><span class="pln">
  bio</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">$</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">[</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">name</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]}</span><span class="pln"> is $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> years old</span><span class="pun">.`);</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  introduceSelf</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="typ">Hi</span><span class="pun">!</span><span class="pln"> I</span><span class="str">'</span><span class="pln">m $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</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>
	وسنستخدم من اﻵن وصاعدًا الصيغة المختصرة في تعريف الدوال.
</p>

<p>
	ندعو الكائنات التي تُبنى كما شرحنا سابقًا بالكائنات الحرفية literal object لأننا كتبنا حرفيًا كل أعضائها عند إنشائها. وهي كائنات مختلفة عن تلك التي تُنسخ عن اﻷصناف، والتي سنلقي عليها نظرة لاحقًا.
</p>

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

<h2 id="dotnotation">
	طريقة النقطة Dot notation للوصول إلى أعضاء الكائن
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_19" style=""><span class="pln">person</span><span class="pun">.</span><span class="pln">age</span><span class="pun">;</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">bio</span><span class="pun">();</span></pre>

<h3 id="-2">
	الكائنات والخاصيات على شكل كائنات
</h3>

<p>
	يمكن للخاصية بحد ذاتها أن تكون كائنًا، جرّب مثلًا أن تغيّر العضو <code>name</code> من الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_21" style=""><span class="kwd">const</span><span class="pln"> person </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><span class="str">"Bob"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Smith"</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_4490_23" style=""><span class="kwd">const</span><span class="pln"> person </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><span class="pln">
    first</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Bob"</span><span class="pun">,</span><span class="pln">
    last</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Smith"</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_4490_25" style=""><span class="pln">person</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">first</span><span class="pun">;</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">last</span><span class="pun">;</span></pre>

<p>
	فإن فعلت ذلك، عليك العودة إلى الشيفرة وتغيير كل شيفرة من الشكل:
</p>

<pre class="ipsCode">name[0];
name[1];
</pre>

<p>
	إلى
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_27" style=""><span class="pln">name</span><span class="pun">.</span><span class="pln">first</span><span class="pun">;</span><span class="pln">
name</span><span class="pun">.</span><span class="pln">last</span><span class="pun">;</span></pre>

<p>
	وإلا لن تعمل التوابع.
</p>

<h2 id="-3">
	استخدام طريقة اﻷقواس في الوصول إلى أعضاء الكائن
</h2>

<p>
	باﻹمكان الوصول إلى أعضاء الكائن باستخدام طريقة اﻷقواس المربعة Bracket notation فبدلًا من استخدام النقطة كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_29" style=""><span class="pln">person</span><span class="pun">.</span><span class="pln">age</span><span class="pun">;</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">first</span><span class="pun">;</span></pre>

<p>
	يمكننا استخدام الأقواس كما في الكود التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_31" style=""><span class="pln">person</span><span class="pun">[</span><span class="str">"age"</span><span class="pun">];</span><span class="pln">
person</span><span class="pun">[</span><span class="str">"name"</span><span class="pun">][</span><span class="str">"first"</span><span class="pun">];</span></pre>

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

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

<p>
	في المثال التالي، يمكن للدالة أن تستخدم الطريقة <code>person[propertyName]</code> للوصول إلى القيمة المخزنة في الخاصية <code>proertyName</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_33" style=""><span class="kwd">const</span><span class="pln"> person </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><span class="str">"Bob"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Smith"</span><span class="pun">],</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">32</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"> logProperty</span><span class="pun">(</span><span class="pln">propertyName</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">person</span><span class="pun">[</span><span class="pln">propertyName</span><span class="pun">]);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

logProperty</span><span class="pun">(</span><span class="str">"name"</span><span class="pun">);</span><span class="pln">
</span><span class="com">// ["Bob", "Smith"]</span><span class="pln">
logProperty</span><span class="pun">(</span><span class="str">"age"</span><span class="pun">);</span><span class="pln">
</span><span class="com">// 32</span></pre>

<h2 id="-4">
	ضبط قيم أعضاء الكائن
</h2>

<p>
	كل ما تعلمناه حتى اللحظة هو الحصول على قيمة أعضاء الكائن object members، لكن باﻹمكان أيضًا ضبط قيمة هذه الأعضاء بالتصريح عن العضو الذي تريد ضبطه (باستخدام طريقة النقطة أو اﻷقواس المربعة) كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_35" style=""><span class="pln">person</span><span class="pun">.</span><span class="pln">age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">45</span><span class="pun">;</span><span class="pln">
person</span><span class="pun">[</span><span class="str">"name"</span><span class="pun">][</span><span class="str">"last"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Cratchit"</span><span class="pun">;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_39" style=""><span class="pln">person</span><span class="pun">.</span><span class="pln">age</span><span class="pun">;</span><span class="pln">
person</span><span class="pun">[</span><span class="str">"name"</span><span class="pun">][</span><span class="str">"last"</span><span class="pun">];</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_37" style=""><span class="pln">person</span><span class="pun">[</span><span class="str">"eyes"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"hazel"</span><span class="pun">;</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">farewell </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</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="str">"Bye everybody!"</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_4490_41" style=""><span class="pln">person</span><span class="pun">[</span><span class="str">"eyes"</span><span class="pun">];</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">farewell</span><span class="pun">();</span><span class="pln">
</span><span class="com">// "Bye everybody!"</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_43" style=""><span class="kwd">const</span><span class="pln"> myDataName </span><span class="pun">=</span><span class="pln"> nameInput</span><span class="pun">.</span><span class="pln">value</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> myDataValue </span><span class="pun">=</span><span class="pln"> nameValue</span><span class="pun">.</span><span class="pln">value</span><span class="pun">;</span></pre>

<p>
	نضيف بعدها هذا العضو الجديد إلى الكائن <code>person</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_47" style=""><span class="pln">person</span><span class="pun">[</span><span class="pln">myDataName</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> myDataValue</span><span class="pun">;</span></pre>

<p>
	ولاختبار اﻷمر، جرّب إضافة الأسطر التالية إلى شيفرتك، أسفل قوس إغلاق الكائنن <code>person</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_45" style=""><span class="kwd">const</span><span class="pln"> myDataName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"height"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> myDataValue </span><span class="pun">=</span><span class="pln"> </span><span class="str">"1.75m"</span><span class="pun">;</span><span class="pln">
person</span><span class="pun">[</span><span class="pln">myDataName</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> myDataValue</span><span class="pun">;</span></pre>

<p>
	جرّب حفظ التغييرات وإعادة تحميل الصفحة ثم إدخال التالي ضمن مربع اﻹدخال النصي:
</p>

<pre class="ipsCode">person.height;
</pre>

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

<h2 id="this">
	لماذا استخدمت الكلمة المحجوزة <code>this</code>
</h2>

<p>
	لربما قد لاحظت شيئًا غريبًا في أسلوبنا في الشيفرة السابقة، ألق نظرة اﻵن على هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_49" style=""><span class="pln">introduceSelf</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="typ">Hi</span><span class="pun">!</span><span class="pln"> I</span><span class="str">'</span><span class="pln">m $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]}.`);</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	لنوضح ذلك من خلال المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_51" style=""><span class="kwd">const</span><span class="pln"> person1 </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="str">"Chris"</span><span class="pun">,</span><span class="pln">
  introduceSelf</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="typ">Hi</span><span class="pun">!</span><span class="pln"> I</span><span class="str">'</span><span class="pln">m $</span><span class="pun">{</span><span class="kwd">this</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="pun">};</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> person2 </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="str">"Deepti"</span><span class="pun">,</span><span class="pln">
  introduceSelf</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="typ">Hi</span><span class="pun">!</span><span class="pln"> I</span><span class="str">'</span><span class="pln">m $</span><span class="pun">{</span><span class="kwd">this</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="pun">};</span></pre>

<p>
	في هذه الحالة، ينتج عن تنفيذ التعليمة <code>()person1.introduceSelf</code> الخرج التالي "Hi! I'm Chris."، بينما ينتج عن تطبيق نفس التابع على كائن آخر <code>()person2.introduceSelf</code> من نفس النوع خرج آخر مناسب للكائن "Hi! I'm Deepti". وعلى الرغم من أن الشيفرة نفسها في الحالتين، لكن أهميتها لن تظهر عند كتابة كائنات حرفية يدويًا، بل عندما تبدأ باستخدام الدوال البانية constructors ﻹنشاء أكثر من كائن من تعريف واحد له وهذا ما نناقشه تاليًا.
</p>

<h2 id="constructors">
	مقدمة إلى الدوال البانية Constructors
</h2>

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

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

<p>
	إليك نسخة أولى من الشكل الذي نتحدث عنه وهو على شكل دالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_53" style=""><span class="kwd">function</span><span class="pln"> createPerson</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">const</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">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
  obj</span><span class="pun">.</span><span class="pln">introduceSelf </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</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="typ">Hi</span><span class="pun">!</span><span class="pln"> I</span><span class="str">'</span><span class="pln">m $</span><span class="pun">{</span><span class="kwd">this</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">return</span><span class="pln"> obj</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُنشئ الدالة وتعيد كائنًا جديدًا في كل مرة نستدعيها، ويضم هذا الكائن عضوين هما:
</p>

<ul>
	<li>
		الخاصية: <code>name</code>.
	</li>
	<li>
		التابع: <code>()introduceSelf</code>.
	</li>
</ul>

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

<p>
	بإمكانك اﻵن إنشاء العدد الذي تريده من الكائنات، بإعادة استخدام الدالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_55" style=""><span class="kwd">const</span><span class="pln"> salva </span><span class="pun">=</span><span class="pln"> createPerson</span><span class="pun">(</span><span class="str">"Salva"</span><span class="pun">);</span><span class="pln">
salva</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span><span class="pln">
salva</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln">
</span><span class="com">// "Hi! I'm Salva."</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> frankie </span><span class="pun">=</span><span class="pln"> createPerson</span><span class="pun">(</span><span class="str">"Frankie"</span><span class="pun">);</span><span class="pln">
frankie</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span><span class="pln">
frankie</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln">
</span><span class="com">// "Hi! I'm Frankie."</span></pre>

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

<ul>
	<li>
		تنشئ كائنًا جديدًا.
	</li>
	<li>
		تربط <code>this</code> بالكائن الجديد، وستتمكن عندها من اﻹشارة إلى الكائن الجديد من خلالها ضمن شيفرة الدالة البانية.
	</li>
	<li>
		تعيد الكائن الجديد.
	</li>
</ul>

<p>
	تبدأ أسماء الدوال البانية عادة بحرف كبير وتسمى باسم نوع الكائن الذي تنشؤه، لهذا سنعيد كتابة مثالنا ليصبح بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_57" style=""><span class="kwd">function</span><span class="pln"> </span><span class="typ">Person</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">this</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="kwd">this</span><span class="pun">.</span><span class="pln">introduceSelf </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</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="typ">Hi</span><span class="pun">!</span><span class="pln"> I</span><span class="str">'</span><span class="pln">m $</span><span class="pun">{</span><span class="kwd">this</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="pun">}</span></pre>

<p>
	ولكي نستدعي الدالة <code>()Person</code> كدالة بانية نستخدم الكلمة <code>new</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_59" style=""><span class="kwd">const</span><span class="pln"> salva </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Person</span><span class="pun">(</span><span class="str">"Salva"</span><span class="pun">);</span><span class="pln">
salva</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span><span class="pln">
salva</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln">
</span><span class="com">// "Hi! I'm Salva."</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> frankie </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Person</span><span class="pun">(</span><span class="str">"Frankie"</span><span class="pun">);</span><span class="pln">
frankie</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span><span class="pln">
frankie</span><span class="pun">.</span><span class="pln">introduceSelf</span><span class="pun">();</span><span class="pln">
</span><span class="com">// "Hi! I'm Frankie."</span></pre>

<h2 id="-5">
	لقد استخدمت الكائنات كثيرًا فيما مضى
</h2>

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

<p>
	فعندما تستخدم التابع النص كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_61" style=""><span class="pln">myString</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">","</span><span class="pun">);</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_63" style=""><span class="kwd">const</span><span class="pln"> myDiv </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">"div"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> myVideo </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">"video"</span><span class="pun">);</span></pre>

<p>
	فأنت تستخدم في الواقع التوابع التي يقدّمها الكائن أو الواجهة البرمجية <a href="https://wiki.hsoub.com/JavaScript/Document" rel="external"><code>Document</code></a>، وعند كل تحميل لصفحة الويب تُنشئ نسخة جديدة عن هذا الكائن تُدعى <code>document</code> تمثّل هيكلية الصفحة بأكملها ومحتواها وغير ذلك من الميزات مثل عناوين URL. أي باختصار، سيمتلك الكائن الذي أنشأته عدة توابع وخاصيات يشترك فيها مع الكائن الأساسي Document.
</p>

<p>
	وهذا الأمر مشابه للكثير من الكائنات والواجهات البرمجية المضمنة في لغة جافا سكريبت مثل المصفوفات <code>Array</code> والمكتبة <code>Math</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4490_65" style=""><span class="kwd">const</span><span class="pln"> myNotification </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Notification</span><span class="pun">(</span><span class="str">"Hello!"</span><span class="pun">);</span></pre>

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

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

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

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

<ul>
	<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%EF%BB%B7%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%D9%8A%D8%A8%D8%AA-r2306/" 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>
	<li>
		<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%A8%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-oop/" rel="">لغة البرمجة بالكائنات Object-Oriented Programming</a>
	</li>
	<li>
		<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="">برمجة الكائنات Objects في جافاسكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%85%D8%AE%D8%AA%D8%B5%D8%B1-%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-oop-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D9%87%D8%A7-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1926/" rel="">مختصر البرمجة كائنية التوجه <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr> وتطبيقها في بايثون</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2305</guid><pubDate>Fri, 19 Apr 2024 12:00:00 +0000</pubDate></item><item><title>&#x62A;&#x648;&#x627;&#x628;&#x639; &#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x646;&#x635;&#x648;&#x635; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2300/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_04/-----.png.a10f614a3dad2a7416d2a4d633cb1484.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%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2296/" rel="">مقال سابق</a> على أبسط أساسيات النصوص في جافا سكريبت، سننتقل في هذا المقال إلى مناقشة العمليات المهمة التي يمكن تنفيذها على النصوص والتوابع الأصلية التي توفرها جافا سكريبت لتحقيق ذلك مثل إيجاد طول سلسلة نصية وضم أو فصل سلسلة نصية وتبديل محرف بآخر وغيرها. ننصحك قبل المتابعة في قراءة هذا المقال بالاطلاع على بعض المقالات السابقة مثل:
</p>

<ol>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">أساسيات علوم الحاسوب</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>
</ol>

<h2 id="">
	السلاسل النصية والكائنات
</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%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="">objects</a>، فعندما ننشئ سلسلة نصية كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_7" style=""><span class="kwd">const</span><span class="pln"> string </span><span class="pun">=</span><span class="pln"> </span><span class="str">"This is my string"</span><span class="pun">;</span></pre>

<p>
	يصبح المتغير قالبًا لكائن نصي وكنتيجة يمكن تطبيق عدد كبير من الخاصيات والتوابع عليه. وللاطلاع على هذه الخاصيات والتوابع يمكنك مراجعة توثيق موسوعة حسوب للكائن <a href="https://wiki.hsoub.com/JavaScript/String" rel="external"><code>String</code></a>. لا حاجة طبعًا أن تربك نفسك بهذه التوابع في بداية رحلتك في <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>

<h2 id="-1">
	إيجاد طول سلسلة نصية
</h2>

<p>
	بإمكانك إنجاز اﻷمر باستخدام الخاصية <code>length</code>، إليك مثالًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_13" style=""><span class="kwd">const</span><span class="pln"> browserType </span><span class="pun">=</span><span class="pln"> </span><span class="str">"mozilla"</span><span class="pun">;</span><span class="pln">
browserType</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span></pre>

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

<h2 id="-2">
	استخلاص محرف محدد من سلسلة نصية
</h2>

<p>
	بإمكانك عمومًا إعادة محرف محدد من سلسلة نصية باستدعاء المتغير الذي يضمها وبعده قوسان مربعان <code>[]</code>يحويان رقم المحرف الذي تريده، فلو أردت مثلًا إعادة المحرف الأول من سلسلة نصية يمكنك كتابة التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_15" style=""><span class="pln">browserType</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span></pre>

<p>
	وتذكر أن الفهرسة تبدأ من الصفر وليس من 1. ولكي تعيد آخر محرف من أي سلسلة نصية يمكن استخدام الخاصية <code>length</code> وفق التقنية التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_17" style=""><span class="pln">browserType</span><span class="pun">[</span><span class="pln">browserType</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></pre>

<p>
	وبما أن طول السلسة "mozilla" هو 7، سيكون رقم المحرف اﻷخير منها هو 6 لأن العد يبدأ من 0. لهذا استخدمنا في الكود أعلاه الأمر <code>length-1</code>.
</p>

<h2 id="-3">
	التحقق من وجود سلسلة نصية ضمن أخرى
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_19" style=""><span class="kwd">const</span><span class="pln"> browserType </span><span class="pun">=</span><span class="pln"> </span><span class="str">"mozilla"</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">browserType</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="str">"zilla"</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">"Found zilla!"</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 zilla here!"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_21" style=""><span class="kwd">const</span><span class="pln"> browserType </span><span class="pun">=</span><span class="pln"> </span><span class="str">"mozilla"</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">browserType</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="str">"zilla"</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">"Found zilla!"</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 zilla here!"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_23" style=""><span class="kwd">const</span><span class="pln"> browserType </span><span class="pun">=</span><span class="pln"> </span><span class="str">"mozilla"</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">browserType</span><span class="pun">.</span><span class="pln">endsWith</span><span class="pun">(</span><span class="str">"zilla"</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">"Found zilla!"</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 zilla here!"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2 id="-4">
	إيجاد موقع سلسلة فرعية ضمن سلسلة أطول
</h2>

<p>
	نستخدم لهذا الغرض التابع <code>()indexOf</code> الذي يأخذ معاملين اﻷول هو السلسلة التي تبحث عنها والثاني اختياري ويشير إلى موقع بداية البحث. يعيد التابع موقع أول ظهور للسلسلة النصية، لكن إن لم يجدها يعيد القيمة <code>1-</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_25" style=""><span class="kwd">const</span><span class="pln"> tagline </span><span class="pun">=</span><span class="pln"> </span><span class="str">"MDN - Resources for developers, by developers"</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">tagline</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"developers"</span><span class="pun">));</span><span class="pln"> </span><span class="com">// 20</span></pre>

<p>
	في مثالنا السابق يبدأ البحث من الموقع <code>0</code>، ولو عددت المحارف بما فيها المسافات الفارغة من البداية فسيكون أول ظهور للسلسلة النصية "developers" في الموقع <code>20</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_27" style=""><span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">tagline</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"x"</span><span class="pun">));</span><span class="pln"> </span><span class="com">// -1</span></pre>

<p>
	يعيد البحث السابق القيمة <code>1-</code> لأن المحرف <code>x</code> غير موجود ضمن السلسلة. طالما أنك تعلمت كيفية إيجاد الظهور اﻷول لسلسلة فرعية ضمن سلسلة أطول، فكيف ستجد ظهورات أخرى؟ يمكنك ذلك بتمرير قيمة أعلى من قيمة الظهور السابق للوسيط الثاني للتابع.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_29" style=""><span class="kwd">const</span><span class="pln"> firstOccurrence </span><span class="pun">=</span><span class="pln"> tagline</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"developers"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> secondOccurrence </span><span class="pun">=</span><span class="pln"> tagline</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"developers"</span><span class="pun">,</span><span class="pln"> firstOccurrence </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</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">firstOccurrence</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 20</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">secondOccurrence</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 35</span></pre>

<p>
	نبلغ التابع في هذه الحالة أن يبدأ البحث عن النص بدءًا من الموقع <code>21</code> (<code>firstOccurrence + 1</code>) وأعاد القيمة <code>35</code> وهو موقع الظهور الثاني.
</p>

<h2 id="-5">
	استخلاص سلسلة نصية فرعية من سلسلة أطول
</h2>

<p>
	وذلك باستخدام التابع <code>()slice</code> الذي يُمرر له معاملان هما:
</p>

<ul>
	<li>
		موقع بداية الاستخلاص.
	</li>
	<li>
		موقع نهاية الاستخلاص ولا يؤخذ المحرف في آخر موقع للاستخلاص. إليك مثالًا:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_31" style=""><span class="kwd">const</span><span class="pln"> browserType </span><span class="pun">=</span><span class="pln"> </span><span class="str">"mozilla"</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">browserType</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">));</span><span class="pln"> </span><span class="com">// "ozi"</span></pre>

<p>
	إن المحرف الموجود في الموقع <code>1</code> هو <code>"o"</code> وفي الموقع <code>4</code> هو <code>"l"</code> لهذا يكون النتيجة هي السلسلة <code>"ozi"</code> التي تبدأ بالمحرف <code>"o"</code> وتنتهي قبل المحرف <code>"l"</code>. أما إذا أردت استخلاص جميع المحارف التي تأتي بعد محرف معين، فلا تحدد قيمة للمعامل الثاني، بل مرر فقط موقع المحرف الذي تريد أن تبدأ الاستخلاص عنده. جرّب اﻵن ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_33" style=""><span class="pln">browserType</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">(</span><span class="lit">2</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "zilla"</span></pre>

<p>
	تُعيد الشيفرة السابقة النص <code>"zilla"</code> لأن المحرف في الموقع <code>2</code> هو <code>"z"</code> ولم نحدد قيمة للمعامل الثاني فستكون النتيجة جميع المحارف من نقطة بداية الاستخلاص حتى نهاية السلسلة. **ملاحظة للتابع <code>()slice</code> خيارات أخرى يمكنك الاطلاع عليها في <a href="https://wiki.hsoub.com/JavaScript/String#String.prototype.slice.28.29" rel="external">توثيق التابع</a> ضمن موسوعة حسوب.
</p>

<h2 id="-6">
	تغيير حالة الحروف
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_35" style=""><span class="kwd">const</span><span class="pln"> radData </span><span class="pun">=</span><span class="pln"> </span><span class="str">"My NaMe Is MuD"</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">radData</span><span class="pun">.</span><span class="pln">toLowerCase</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">radData</span><span class="pun">.</span><span class="pln">toUpperCase</span><span class="pun">());</span></pre>

<h2 id="-7">
	تحديث أجزاء من النص
</h2>

<p>
	يمكن استبدال سلسلة فرعية من نص بسلسلة أخرى باستخدام التابع <code>()replace</code>. ولتجريب الأمر نحاول أن نستبدل في المثال التالي السلسلة التي مررناها كمعامل أول للتابع بالسلسلة التي تمثل المعامل الثاني:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_37" style=""><span class="kwd">const</span><span class="pln"> browserType </span><span class="pun">=</span><span class="pln"> </span><span class="str">"mozilla"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> updated </span><span class="pun">=</span><span class="pln"> browserType</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">"moz"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"van"</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">updated</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "vanilla"</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">browserType</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "mozilla"</span></pre>

<p>
	وتجدر الملاحظة أن التابع <code>()replace</code> مثل العديد من توابع الكائن النصي لا يغير الكائن الذي استدعاه بل يعيد سلسلة نصية جديدة، لكن إن أردت تحديث المتغير اﻷصلي <code>browserType</code>، فعليك تنفيذ الشيفرة التالية مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_39" style=""><span class="kwd">let</span><span class="pln"> browserType </span><span class="pun">=</span><span class="pln"> </span><span class="str">"mozilla"</span><span class="pun">;</span><span class="pln">
browserType </span><span class="pun">=</span><span class="pln"> browserType</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">"moz"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"van"</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">browserType</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "vanilla"</span></pre>

<p>
	كما عليك أن تصرح عن <code>browserType</code> في هذه الحالة باستخدام <code>let</code>وليس <code>const</code> ﻷن الثابت لا يمكن تحديث قيمته. وانتبه إلى أن التابع <code>()replace</code> يستبدل السلسلة عند أول ظهور فقط، لكن إن أردت استبدال كل حالات الظهور، عليك استخدام التابع <code>()replaceAll</code>
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6236_41" style=""><span class="kwd">let</span><span class="pln"> quote </span><span class="pun">=</span><span class="pln"> </span><span class="str">"To be or not to be"</span><span class="pun">;</span><span class="pln">
quote </span><span class="pun">=</span><span class="pln"> quote</span><span class="pun">.</span><span class="pln">replaceAll</span><span class="pun">(</span><span class="str">"be"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"code"</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">quote</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "To code or not to code"</span></pre>

<h2 id="-8">
	تطبيقات عملية
</h2>

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

<h3 id="-9">
	فلترة رسائل المعايدة
</h3>

<p>
	عليك في هذا التمرين وضع رسائل المعايدة بعيد الميلاد على شكل قائمة، لها ضع الاختبار المناسب في البنية الشرطية <code>()if</code> واختبر كل سلسلة نصية واطبعها ضمن القائمة إن كانت رسالة عيد ميلاد.
</p>

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

<h3 id="-10">
	تصحيح حالة بداية الكلمات
</h3>

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

<ol>
	<li>
		حول حالة جميع الحروف في السلسلة النصية الموجودة في المتغير إلى حروف صغيرة وخزنها في متغير جديد.
	</li>
	<li>
		استخلص الحرف اﻷول من السلسلة وخزّنه في متغير آخر.
	</li>
	<li>
		استبدل الحرف اﻷول من المتغير الذي أنشأته في الخطوة 2 بقيمة المتحول الذي أنشأته في الخطوة 2 بعد تحويل قيمته إلى حروف كبيرة.
	</li>
	<li>
		غيّر قيمة المتغير <code>result</code> كي تساوي نتيجة الخطوة 3.
	</li>
</ol>

<p>
	<strong>ملاحظة وتلميح:</strong> ليس من الضروري أن يكون معامل توابع السلاسل النصية نصًا بل قد يكون عددًا أو متغيرًا أو تابعًا آخر.
</p>

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

<h3 id="-11">
	إنشاء نص جديد من أجزاء قديمة
</h3>

<p>
	تتكون المصفوفة في هذا التمرين من عدة سلاسل نصية تتضمن معلومات عن محطات القطار شمال إنجلترا. وتمثل السلاسل النصية بيانات تضم رمز المحطة المكوّن من ثلاثة حروف متبوعًا بمجموعة بيانات تفهمها اﻵلة يليها فاصلة منقوطة يليها اسم المحطة المقروء بالنسبة للبشر مثل<code>MAN675847583748sjt567654;Manchester Piccadilly</code> لهذا نريد استخلاص رمز المحطة واسمها ووضعهما في سلسلة جديدة لها الشكل التالي: <code>MAN: Manchester Piccadilly</code>. ننصحك بتجريب الخطوات التالية:
</p>

<ol>
	<li>
		استخلص رمز المحطة المكون من ثلاثة حروف وخزنه في متغير جديد.
	</li>
	<li>
		جد موقع الفاصلة المنقوطة.
	</li>
	<li>
		استخدم موقع الفاصلة المنقوطة في استخلاص اسم المحطة المقروء بالنسبة للبشر وخزّنه في متغير آخر.
	</li>
	<li>
		ضم قيمتي آخر متغيرين مع سلسلة من حروف مناسبة لتحصل على الصيغة النهائية.
	</li>
	<li>
		غيّر قيمة المتغير <code>result</code> كي تساوي النتيجة النهائية.
	</li>
</ol>

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

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

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

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

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2296/" rel="">أساسيات التعامل مع النصوص في جافا سكريبت</a>
	</li>
	<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%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="">السلاسل النصية (strings) في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D9%86%D9%91%D8%B5%D9%88%D8%B5-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%91%D8%A9-%D8%AA%D9%86%D8%B8%D9%8A%D9%85-javascript-r14/" rel="">تصميم النّصوص البرمجيّة: تنظيم JavaScript</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-primitives-methods-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r815/" rel="">توابع الأنواع الأولية (primitives methods) في جافاسكربت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2300</guid><pubDate>Thu, 18 Apr 2024 12:07:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; &#x627;&#x644;&#x62A;&#x64A; &#x62A;&#x639;&#x64A;&#x62F; &#x642;&#x64A;&#x645;&#x64B;&#x627; &#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%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D8%B9%D9%8A%D8%AF-%D9%82%D9%8A%D9%85%D9%8B%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2298/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_04/1435359033_.png.94a8ba40d95d91e5150270f6ffa69349.png" /></p>
<p>
	بدأنا في المقال السابق شرح طريقة <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AF%D9%88%D8%A7%D9%84-%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%83-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2293/" 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>
	</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-%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/" rel="">أساسيات جافا سكريبت</a>
	</li>
</ol>

<h2 id="-1">
	ما هي القيم المُعادة Return values
</h2>

<p>
	القيمة المعادة هي ما يحمله معناها تمامًا، أي القيم التي تُعيدها الدوال عندما يكتمل تنفيذها. ومن المؤكد أنك واجهت هذا النوع من القيم مرات عدة لكنك لم تفكر بها صراحة.
</p>

<p>
	سنعيد طرح مثال من <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AF%D9%88%D8%A7%D9%84-%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%83-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2293/" rel="">المقال السابق</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7869_10" style=""><span class="kwd">const</span><span class="pln"> myText </span><span class="pun">=</span><span class="pln"> </span><span class="str">"The weather is cold"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> newString </span><span class="pun">=</span><span class="pln"> myText</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">"cold"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"warm"</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">newString</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Should print "The weather is warm"</span><span class="pln">
</span><span class="com">// the replace() string function takes a string,</span><span class="pln">
</span><span class="com">// replaces one substring with another, and returns</span><span class="pln">
</span><span class="com">// a new string with the replacement made</span></pre>

<p>
	تُستدعى الدالة <code>()replace</code> للتعامل مع النص <code>myText</code> وتُمرر لها قيمتان:
</p>

<ul>
	<li>
		النص الذي نريد إيجاده ('cold').
	</li>
	<li>
		النص الذي نستبدله به ('warm').
	</li>
</ul>

<p>
	عندما ينتهي تنفيذ الدالة تعيد قيمة جديدة هي نص جديد بعد تنفيذ عملية الاستبدال. وتُخزّن النتيجة في الشيفرة السابقة والتي تتضمن هذه القيمة المعادة في المتغير <code>newString</code>.
</p>

<p>
	إن عُدت إلى توثيق الدالة <code><a href="https://wiki.hsoub.com/JavaScript/String/replace" rel="external">()replace</a></code> في موسوعة حسوب ستجد معلومات كافية ومفيدة من المعلومات حول القيم المعادة وسنحاول اﻹشارة عليها ما أمكن في هذا المقال.
</p>

<p>
	ولا تعيد بعض الدوال أية قيم (يُيشار في توثيق هذه الدوال عادة إلى القيمة المعادة على الشكل غير محدد undefined أو لا توجد قيمة void). فلا تعيد مثلًا الدالة <code>displayMessage</code> التي بنيناها في المقال السابق أية قيمة عند تنفيذها، بل تعرض فقط صندوق الرسائل على الشاشة.
</p>

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

<h2 id="-2">
	استخدام القيمة المعادة في دوال بنيتها
</h2>

<p>
	كي تعيد قيمة من دالة مخصصة، استخدم التعليمة <code>return</code>. لقد رأينا ذلك سابقًا في المثال. إذ ترسم الدالة 100 دائرة عشوائية ضمن العنصر <code>&lt;canvas&gt;</code> في ملف HTML:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7869_14" style=""><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"> WIDTH</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">WIDTH</span><span class="pun">),</span><span class="pln"> random</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">
    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></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7869_16" style=""><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></pre>

<p>
	كما يمكن كتابة الدالة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7869_18" style=""><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">const</span><span class="pln"> result </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"> number</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> result</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لكن بالطبع النسخة اﻷولى أسرع وأصغر.
</p>

<p>
	نعيد نتيجة الحسابات <code>Math.floor(Math.random() * number)</code> كل مرة نستدعي فيها الدالة، وتظهر هذه القيمة في مكان استدعاء الدالة ومن ثم تتابع الشيفرة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7869_20" style=""><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">WIDTH</span><span class="pun">),</span><span class="pln"> random</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></pre>

<p>
	فلو أعادت الاستدعاءات الثلاث للدالة <code>()random</code> القيم بالترتيب <code>500</code> و <code>200</code> و <code>35</code> سيكون تنفيذ السطر في الواقع كما لو كان على الشكل:
</p>

<pre class="ipsCode">ctx.arc(500, 200, 35, 0, 2 * Math.PI);
</pre>

<p>
	تُستدعى الدوال <code><a href="https://wiki.hsoub.com/JavaScript/Math/random" rel="external">()random</a></code> في سطر الشيفرة السابق أولًا ومن ثم توضع نتيجة تنفيذها (القيم المعادة) مكانها ثم يُنفّذ السطر.
</p>

<h2 id="-3">
	تطبيق عملي: تابع خاص يعيد قيمة
</h2>

<p>
	نحاول في هذا التطبيق بناء دالة خاصة بنا تعيد قيمة، لهذا اتبع الخطوات التالية:
</p>

<ol>
	<li>
		انسخ الملف إلى حاسوبك، وهي صفحة بسيطة تضم عنصر إدخال نصي <code>&lt;input&gt;</code> وفقرة نصية <code>&lt;p&gt;</code>. كما يوجد عنصر <code>&lt;script&gt;</code> لتخزين مرجع إلى كل من العنصرين السابقين في متغيرين.
	</li>
	<li>
		أضف دالة مفيدة ما إلى العنصر <code>&lt;script&gt;</code> تحت ما هو موجود:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7869_23" style=""><span class="kwd">function</span><span class="pln"> squared</span><span class="pun">(</span><span class="pln">num</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"> num </span><span class="pun">*</span><span class="pln"> num</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"> cubed</span><span class="pun">(</span><span class="pln">num</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"> num </span><span class="pun">*</span><span class="pln"> num </span><span class="pun">*</span><span class="pln"> num</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"> factorial</span><span class="pun">(</span><span class="pln">num</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">num </span><span class="pun">&lt;</span><span class="pln"> </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="kwd">undefined</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">num </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">return</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"> x </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">
  </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x </span><span class="pun">&gt;</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">
    num </span><span class="pun">*=</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
    x</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"> num</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا غموض في شيفرة الدالتين <code>()squared</code> و <code>()cubed</code> اللتان تعيدان مربع ومكعب العدد الذي يُمرر إليهما، أما الدالة <code>()factorial</code> فتعيد قيمة العاملي <code>!</code> للعدد الذي يُمرر إليها (العاملي هو جداء تناقصي للعدد حتى الواحد).
</p>

<ol start="3">
	<li>
		أضف طريقة لطباعة معلومات عن العدد الذي تدخله في مربع اﻹدخال النصي من خلال معالج الحدث التالي تحت الدوال الموجودة:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7869_25" style=""><span class="pln">input</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"> num </span><span class="pun">=</span><span class="pln"> parseFloat</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="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isNaN</span><span class="pun">(</span><span class="pln">num</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">"You need to enter a number!"</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="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">num</span><span class="pun">}</span><span class="pln"> squared is $</span><span class="pun">{</span><span class="pln">squared</span><span class="pun">(</span><span class="pln">num</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">num</span><span class="pun">}</span><span class="pln"> cubed is $</span><span class="pun">{</span><span class="pln">cubed</span><span class="pun">(</span><span class="pln">num</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">num</span><span class="pun">}</span><span class="pln"> factorial is $</span><span class="pun">{</span><span class="pln">factorial</span><span class="pun">(</span><span class="pln">num</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>

<ol start="4">
	<li>
		احفظ التغييرات على الشيفرة وحمّل الصفحة من جديد في المتصفح.
	</li>
</ol>

<p>
	إليك بعض اﻹيضاحات حول معالج الحدث <code>addEventListener</code> في الخطوة الثالثة:
</p>

<ul>
	<li>
		بإضافة مترصد للحدث <code>change</code> ستُنفَّذ الدالة غير المسماة (المعامل الثاني لمترصد الحدث) في كل مرة يحدث فيها تغيير على عنصر اﻹدخال النصي، أي في كل مرة نكتب فيه قيمة جديدةً وتُرسل (مثل إدخال قيمة وإبعاد التركيز عن المربع النصي بالضغط على الزر Tab أو Return). تُخزّن القيمة الموجودة في المربع النصي<code>input</code> عند تنفيذ الدالة غير المسماة في الثابت <code>num</code>.
	</li>
	<li>
		تطبع عبارة <code>if</code> رسالة خطأ إن لم تكن القيمة المدخلة عددًا. إذ تتحقق العبارة الشرطية إذا ما أعادت الدالة <code>isNaN(num)</code> القيمة <code>true</code>. وما تفعله هذه الدالة هو التحقق فيما لو كانت القيمة التي تمرر إليها عددًا أم لا، وتعيد <code>true</code> إن كانت بالفعل عددًا و <code>false</code> إن لم يكن كذلك.
	</li>
	<li>
		إن أعاد الشرط القيمة <code>false</code>، ستكون القيمة عددًا، وتطبع الدالة جملة ضمن الفقرة النصية توضح قيمة مربع ومكعب وعاملي العدد المدخل. إذ تستدعي العبارة الدوال <code>()squared</code> و <code>()cubed</code> و <code>()factorial</code> لحساب القيم الموافقة.
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: إن كانت هناك أية مشاكل في تنفيذ هذا التمرين، وازن بين ما كتبته وبين النسخة الجاهزة من هذا التمرين على جت-هب (نفّذه مباشرة إن أردت!)، أو اطلب المساعدة.
</p>

<h2 id="-4">
	حان دورك اﻵن لكتابة الدالة الخاصة بك في جافا سكريبت
</h2>

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

<p>
	إليك بعض التلميحات المفيدة اﻷخرى عن الدوال:
</p>

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

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

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

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

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

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AF%D9%88%D8%A7%D9%84-%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%83-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2293/" rel="">إنشاء دوال خاصة بك في جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r620/" rel="">الدوال Functions في جافاسكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%88%D8%A5%D8%B9%D8%A7%D8%AF%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%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-r2286/" rel="">الدوال وإعادة استخدام الشيفرة في جافا سكريبت</a>
	</li>
	<li>
		<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>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D9%8A%D8%B2%D8%A7%D8%AA-%D8%A7%D9%84%D8%AC%D8%AF%D9%8A%D8%AF%D8%A9-%D9%81%D9%8A-es6-%D9%86%D8%B7%D8%A7%D9%82-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA%D8%8C-%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%88%D8%A7%D9%84%D9%85%D8%B9%D8%A7%D9%85%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%A8%D8%AF%D8%A6%D9%8A%D8%A9-r567/" rel="">الميزات الجديدة في ES6: نطاق المتغيرات، الدوال السهمية والمعاملات المبدئية</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2298</guid><pubDate>Sun, 14 Apr 2024 12:01:02 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x646;&#x635;&#x648;&#x635; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2296/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_04/--.png.945e002c46e330a36bf47df68b7efb54.png" /></p>
<p>
	نلقي الضوء في هذا المقال على طرق التعامل مع السلاسل النصية Strings، التي تمثل في لغة جافا سكريبت وفي لغات البرمجة عمومً الأجزاء المقتطفة من نص ما، ونناقش ما عليك معرفته بشكل أساسي حول السلاسل النصية مثل إنشائها وتجاوز إشارات التنصيص (استخدامها كما هي دون أية دلالات) وضم أو دمج عدة سلاسل نصية مع بعضها البعض. ننصحك قبل المتابعة في قراءة هذا المقال بالاطلاع على بعض المقالات السابقة مثل:
</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>
</ol>

<h2 id="-1">
	قوة الكلمات!
</h2>

<p>
	الكلمات هي أساس التواصل البشري والويب وسط معرفي مبني أساسًا على النصوص وقد صممت لتعزز التواصل بين البشر وتبادل المعلومات، لهذا من المهم جدًا التحكم بطريقة عرض تلك النصوص. تتيح لك لغة التوصيف <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://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/" rel="">بالتعرف على لغة جافا سكريبت</a> تتضمن شكلًا من أشكال التعامل مع النصوص.
</p>

<h2 id="-2">
	التصريح عن السلاسل النصية
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_14" style=""><span class="kwd">const</span><span class="pln"> string </span><span class="pun">=</span><span class="pln"> </span><span class="str">"The revolution will not be televised."</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">string</span><span class="pun">);</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_12" style=""><span class="kwd">const</span><span class="pln"> badString1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">This</span><span class="pln"> is a test</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> badString2 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'</span><span class="typ">This</span><span class="pln"> is a test</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> badString3 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">This</span><span class="pln"> is a test</span><span class="str">';</span></pre>

<p>
	لن تعمل الأسطر السابقة، لأن أي قيمة نصية دون إشارتي تنصيص حولها سيفترضها المتصفح أسماءً لمتغيرات أو خاصيات أو كلمات محجوزة وما شابه. وعندما لا يجد المتصفح ما افترضه سيعرض رسالة خطأ (مثل "missing; before statement" بمعنى "إغفال ; قبل التصريح"). وعندما يرى المتصفح بداية السلسلة النصية لكنه لا يرى نهايتها التي تشير إليها علامة التنصيص الثانية سيعرض رسالة خطأ تشير إلى أنك لم تُنهي السلسلة النصية كما يجب ("unterminated string literal"). فإن واجهتك رسائل خطأ مشابهة لما ذكرناه فعد إلى شيفرتك البرمجية وتحقق من إشارات التنصيص حول السلاسل النصية.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_10" style=""><span class="kwd">const</span><span class="pln"> badString </span><span class="pun">=</span><span class="pln"> string</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">badString</span><span class="pun">);</span></pre>

<p>
	سيعمل هذا المثال فقط إن صرحت بداية عن المتغير <code>string</code>، وسيكون للثابت <code>badString</code> قيمة <code>string</code> نفسها.
</p>

<h2 id="-3">
	علامة التنصيص المفردة والمزدوجة والمائلة
</h2>

<p>
	بإمكانك أن تختار علامة التنصيص المفردة (<code>'</code>) أو المزدوجة (<code>"</code>) أو المائلة (```) لإحاطة السلسلة النصية. إليك مثالًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_16" style=""><span class="kwd">const</span><span class="pln"> single </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Single quotes'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Double quotes"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> backtick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Backtick</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">single</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="kwd">double</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">backtick</span><span class="pun">);</span></pre>

<p>
	ولا بد من استخدام نفس إشارة التنصيص في بداية ونهاية السلسلة وإلا سترى رسالة خطأ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_19" style=""><span class="kwd">const</span><span class="pln"> badQuotes </span><span class="pun">=</span><span class="pln"> </span><span class="str">'This is not allowed!";</span></pre>

<p>
	وبإمكانك عمومًا استخدام العلامات المزدوجة أو المفردة وفقًا لرغبتك الشخصية فلكلاهما العمل نفسه ومن اﻷفضل من الناحية العملية اختيار أحد اﻷسلوبين واتباعه في كامل مشروعك. وتُدعى السلاسل النصية المعرّفة بعلامة التنصيص المائلة بالقوالب المفسّرة template literals وهي مشابه من الناحية العامة للسلاسل النصية العادية مع بعض الميزات الخاصة:
</p>

<ul>
	<li>
		بإمكانك إدراج شيفرة جافا سكريبت ضمنها.
	</li>
	<li>
		بإمكانك التصريح عن القوالب المفسّرة على عدة أسطر.
	</li>
</ul>

<h2 id="-4">
	إدراج شيفرة جافا سكريبت ضمن نص
</h2>

<p>
	بإمكانك تغليف شيفرة جافا سكريبت لعرض نتيجتها ضمن سلسلة نصية ضمن القالب <code>{}$</code>. إليك مثالًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_21" style=""><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Chris"</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="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">name</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">greeting</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "Hello, Chris"</span></pre>

<p>
	استخدم نفس التقنية أيضًا لضم متغيرين معًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_23" style=""><span class="kwd">const</span><span class="pln"> one </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello, "</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> two </span><span class="pun">=</span><span class="pln"> </span><span class="str">"how are you?"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> joined </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">one</span><span class="pun">}</span><span class="pln">$</span><span class="pun">{</span><span class="pln">two</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">joined</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "Hello, how are you?"</span></pre>

<p>
	تُدعى عملية ضم السلاسل النصية بهذه الطريقة بتجاوز أو دمج النصوص concatenation
</p>

<h3 id="-5">
	سياق عملية التجاور
</h3>

<p>
	لنلق نظرة على عملية التجاور من خلال المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9520_27" style=""><span class="tag">&lt;button&gt;</span><span class="pln">Press me</span><span class="tag">&lt;/button&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">"greeting"</span><span class="tag">&gt;&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_29" style=""><span class="kwd">const</span><span class="pln"> button </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">function</span><span class="pln"> greet</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">"What is your name?"</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"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"#greeting"</span><span class="pun">);</span><span class="pln">
  greeting</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">Hello</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">name</span><span class="pun">},</span><span class="pln"> nice to see you</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"> greet</span><span class="pun">);</span></pre>

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

<p>
	استخدمنا في الشيفرة السابقة الدالة <code>()window.prompt</code> التي تطلب من المستخدم اﻹجابة عن سؤال ضمن نافذة منبثقة يعرضها المتصفح، ويُخزّن النص الذي يكتبه ضمن متغيّر وهو <code>name</code> في حالتنا. ونعرض بعد ذلك نصًا يُظهر الاسم وقد أُدرج ضمن رسالة ترحيبية.
</p>

<h3 id="-6">
	دمج السلاسل النصية باستخدام "+"
</h3>

<p>
	يمكن استخدام اﻷسلوب مع القوالب المفسّرة وليس مع السلاسل النصية النمطية، لكن باﻹمكان ضم سلسلتين نمطيتين باستخدام<br>
	العامل <code>+</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_31" style=""><span class="kwd">const</span><span class="pln"> greeting </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</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"> </span><span class="str">"Chris"</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">greeting </span><span class="pun">+</span><span class="pln"> </span><span class="str">", "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "Hello, Chris"</span></pre>

<p>
	لكن القوالب المفسرة تسهّل قراءة الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_33" style=""><span class="kwd">const</span><span class="pln"> greeting </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</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"> </span><span class="str">"Chris"</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">$</span><span class="pun">{</span><span class="pln">greeting</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="com">// "Hello, Chris"</span></pre>

<h3 id="-7">
	تضمين عبارات برمجية ضمن السلاسل النصية
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_35" style=""><span class="kwd">const</span><span class="pln"> song </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Fight the Youth"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> score </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">const</span><span class="pln"> highestScore </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">const</span><span class="pln"> output </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">I like the song $</span><span class="pun">{</span><span class="pln">song</span><span class="pun">}.</span><span class="pln"> I gave it a score </span><span class="kwd">of</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">
  </span><span class="pun">(</span><span class="pln">score </span><span class="pun">/</span><span class="pln"> highestScore</span><span class="pun">)</span><span class="pln"> </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">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">output</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "I like the song Fight the Youth. I gave it a score of 90%."</span></pre>

<h2 id="-8">
	النص متعدد اﻷسطر
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_37" style=""><span class="kwd">const</span><span class="pln"> newline </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">One</span><span class="pln"> day you finally knew
what you had to </span><span class="kwd">do</span><span class="pun">,</span><span class="pln"> and began</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">newline</span><span class="pun">);</span><span class="pln">

</span><span class="com">/*
One day you finally knew
what you had to do, and began,
*/</span></pre>

<p>
	ولتنفيذ الفكرة نفسها باستخدام السلاسل النصية النمطية لا بد من استخدام محرف الانتقال إلى سطر جديد (<code>n\</code>) ضمن السلسلة النصية وفي المكان الذي ينبغي الانتقال يه إلى السطر الجديد. إليك مثالًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_39" style=""><span class="kwd">const</span><span class="pln"> newline </span><span class="pun">=</span><span class="pln"> </span><span class="str">"One day you finally knew\nwhat you had to do, and began,"</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">newline</span><span class="pun">);</span><span class="pln">

</span><span class="com">/*
One day you finally knew
what you had to do, and began,
*/</span></pre>

<h2 id="-9">
	تضمين إشارة التنصيص ضمن سلسلة نصية
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_41" style=""><span class="kwd">const</span><span class="pln"> badQuotes </span><span class="pun">=</span><span class="pln"> </span><span class="str">"She said "</span><span class="pln">I think so</span><span class="pun">!</span><span class="str">""</span><span class="pun">;</span></pre>

<p>
	ومن إحدى الطرق المتبعة لحل المشكلة استخدام نوع من علامات التنصيص ضمن السلسلة وآخر لتحديد بدايتها ونهايتها كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_43" style=""><span class="kwd">const</span><span class="pln"> goodQuotes1 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'She said "I think so!"'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> goodQuotes2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">She</span><span class="pln"> said </span><span class="str">"I'm not going in there!"</span><span class="pun">`;</span></pre>

<p>
	أما الخيار اﻵخر فهو <em>تجاوز escape</em> إشارة التنصيص ضمن النص ويقصد بذلك إهمال وظيفتها كبداية أو نهاية السلسلة واعتبارها محرفًا عاديًا أي اعتبارها كنص وليس جزءًا من الشيفرة. لتنفيذ ذلك في جافا سكريبت نضع شرطة مائلة عكسية <code>\</code> قبل المحرف الذي نريد تجاوزه. إليك مثالًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_45" style=""><span class="kwd">const</span><span class="pln"> bigmouth </span><span class="pun">=</span><span class="pln"> </span><span class="str">'I\'ve got no right to take my place…'</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">bigmouth</span><span class="pun">);</span></pre>

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

<h2 id="-10">
	اﻷعداد مقابل السلاسل النصية
</h2>

<p>
	ما الذي سيحدث إن حاولت ضم عدد إلى سلسلة نصية؟ لنجرّب ذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_47" style=""><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Front "</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">242</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">$</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">number</span><span class="pun">}`);</span><span class="pln"> </span><span class="com">// "Front 242"</span></pre>

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

<ul>
	<li>
		تحوّل الدالة <code>()Number</code> القيمة التي تمرر إليها إلى عدد إن كان ذلك ممكنًا، جرّب ذلك:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_49" style=""><span class="pln">  </span><span class="kwd">const</span><span class="pln"> myString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"123"</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> myNum </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">myString</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="kwd">typeof</span><span class="pln"> myNum</span><span class="pun">);</span><span class="pln">
  </span><span class="com">// number</span></pre>

<ul>
	<li>
		تحوّل الدالة <code>()String</code>القيمة التي تمرر إليها إلى نص، جرّب ذلك:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9520_51" style=""><span class="pln">  </span><span class="kwd">const</span><span class="pln"> myNum2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">123</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> myString2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">(</span><span class="pln">myNum2</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="kwd">typeof</span><span class="pln"> myString2</span><span class="pun">);</span><span class="pln">
  </span><span class="com">// string</span></pre>

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

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

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

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

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B1%D9%8A%D8%A7%D8%B6%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%A7%EF%BB%B7%D8%B9%D8%AF%D8%A7%D8%AF-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2289/" rel="">العمليات الرياضية على اﻷعداد في جافا سكريبت</a>
	</li>
	<li>
		<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="">السلاسل النصية (strings) في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D9%86%D9%91%D8%B5%D9%88%D8%B5-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%91%D8%A9-%D8%AA%D9%86%D8%B8%D9%8A%D9%85-javascript-r14/" rel="">تصميم النّصوص البرمجيّة: تنظيم JavaScript</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-primitives-methods-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r815/" rel="">توابع الأنواع الأولية (primitives methods) في جافاسكربت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2296</guid><pubDate>Tue, 09 Apr 2024 12:07:00 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62F;&#x648;&#x627;&#x644; &#x62E;&#x627;&#x635;&#x629; &#x628;&#x643; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627; &#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AF%D9%88%D8%A7%D9%84-%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%83-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2293/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_04/1078948966_.png.5d16fe21201e70772f49bd7ef75dc27d.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%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/" rel="">ساسيات جافا سكريبت</a> كما شرحناها في سلسلة المقالات السابقة.
	</li>
</ol>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_7" style=""><span class="pln">alert</span><span class="pun">(</span><span class="str">"This is a message"</span><span class="pun">);</span></pre>

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

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

<h2 id="-2">
	الدالة اﻷساسية
</h2>

<p>
	لنبدأ بتشكيل دالة أساسية مع التقيد بنفس قواعد التسمية المتبعة عند تسمية المتغيرات، فلا مشكلة في ذلك طالما أن الدوال يتبعها قوسان وبالتالي يمكن تمييزها عن المتغيرات.
</p>

<ol>
	<li>
		أنشئ نسخة خاصة بك من <a href="https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/functions/function-start.html" rel="external nofollow">ملف HTM الخاص بالتمرين</a> وستجده بسيطًا يحتوي جسمه على زر واحد ويضم أيضًا تنسيقات CSS أساسية لتنسيق صندوق الرسالة، كما ستجد العنصر <code>&lt;script&gt;</code> الذي يضم شيفرة جافا سكريبت الخاصة بالتمرين
	</li>
	<li>
		أضف الشيفرة التالية ضمن العنصر <code>&lt;script&gt;</code>:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_9" style=""><span class="kwd">function</span><span class="pln"> displayMessage</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>function</code> والتي تعني أننا نعرّف تابعًا يليها الاسم الذي نريد تسمية الدالة به يليه زوج من الأقواس وزوج من اﻷقواس المعقوصة. ونضع أية معاملات نريد نعطيها للدالة داخل القوسين العاديين، بينما نضع الشيفرة التي تنفذها الدالة بين القوسين المعقوصين.
</p>

<ol start="2">
	<li>
		أضف أخيرًا الشيفرة التالية ضمن القوسين المعقوصين:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_11" style=""><span class="kwd">const</span><span class="pln"> body </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">const</span><span class="pln"> panel </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">"div"</span><span class="pun">);</span><span class="pln">
panel</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">"class"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"msgBox"</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">panel</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> msg </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">
msg</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"This is a message box"</span><span class="pun">;</span><span class="pln">
panel</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">msg</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> closeBtn </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">
closeBtn</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"x"</span><span class="pun">;</span><span class="pln">
panel</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">closeBtn</span><span class="pun">);</span><span class="pln">

closeBtn</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">
  panel</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">panel</span><span class="pun">),</span><span class="pln">
</span><span class="pun">);</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_13" style=""><span class="kwd">const</span><span class="pln"> body </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">;</span></pre>

<p>
	يستخدم القسم الثاني أحد دوال الواجهة البرمجية <code>()document.createElement</code> ﻹنشاء عنصر <code>&lt;div&gt;</code> ثم يخزّن مرجعًا إليه ضمن ثابت يُدعى <code>panel</code>. سيمثّل هذا العنصر الحاوية الخارجية لصندوق الرسائل.
</p>

<p>
	نستخدم بعد ذلك دالة أخرى <code>()Element.setAtrtribute</code> لضبط السمة <code>class</code> العائدة للوحة صندوق الرسائل على <code>msgbox</code> كي يسهل تنسيق العنصر. فلو ألقيت نظرة على تنسيقات الصفحة ستجد أنها تحتوي على الصنف <code>msgbox.</code> لتنسيق صندوق الرسائل ومحتواه.
</p>

<p>
	نستدعي أخيرًا الدالة <code>()Node.appendChild</code> للثابت <code>body</code> الذي عرَفناه سابقًا والتي تضع عنصرًا ضمن آخر كابن له. وخصصنا العنصر <code>&lt;div&gt;</code> ليكون ابنًا للعنصر <code>&lt;body&gt;</code> والسبب في ذلك ألا يظهر العنصر الذي ننشئه في مكانه الافتراضي في الصفحة بل نريد وضعه في مكان نخصصه له.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_15" style=""><span class="kwd">const</span><span class="pln"> panel </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">"div"</span><span class="pun">);</span><span class="pln">
panel</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">"class"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"msgBox"</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">panel</span><span class="pun">);</span></pre>

<p>
	نستخدم تاليًا الدالتين <code>()createElement</code> و <code>()appendChilde</code> اللتان رأينا عملهما سابقًا في إنشاء عنصري فقرة نصية <code>&lt;p&gt;</code> والحاقهما في الصفحة كابنين للعنصر <code>&lt;div&gt;</code>. وبعدها نستخدم الخاصية <code>Node.textContent</code> والتي تمثل المحتوى النصي للفقرة لوضع الرسالة المطلوبة ضمن الفقرة النصية وإشارة "x" كعنوان للزر لتعكس وظيفته وهي إغلاق صندوق الرسائل.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_17" style=""><span class="kwd">const</span><span class="pln"> msg </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">
msg</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"This is a message box"</span><span class="pun">;</span><span class="pln">
panel</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">msg</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> closeBtn </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">
closeBtn</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"x"</span><span class="pun">;</span><span class="pln">
panel</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">closeBtn</span><span class="pun">);</span></pre>

<p>
	ثم نستدعي في النهاية الدالة <code>()addEveentListener</code> ﻹضافة دالة (دالة سهمية غير مسماة) تُستدعى عندما ينقر المستخدم على الزر ومهمتها حذف العنصر الذي يمثل صندوق الرسائل بأكمله من الصفحة. يُمرر للتابع <code>()addEveentListener</code> الذي يمكن أن يستخدمه أي عنصر في الصفحة دالة أخرى واسم الحدث الذي ينبغي ترصده وهو في حالتنا "click"، أي ستُنفّذ الدالة عندما ينقر المستخدم على الزر ( سنتحدث بتفصيل أكثر عن اﻷحداث في مقال "<a href=")" rel="">مدخل إلى اﻹحداث في جافا سكريبت</a>. أما الدالة التي نستخدمها عند وقوع الحدث فتضم دالة أخرى من دوال الواجهة البرمجية لشجرة المستند DOM وهي <code>()Node.removeChild</code> التي تزيل ابنًا محددًا من أبناء العنصر وهو في حالتنا العنصر <code>&lt;div&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_19" style=""><span class="pln">closeBtn</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"> panel</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">panel</span><span class="pun">));</span></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8270_21" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"msgBox"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">This is a message box</span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;button&gt;</span><span class="pln">x</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

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

<h2 id="-3">
	استدعاء الدالة
</h2>

<p>
	عرفّنا اﻵن الدالة التي نريدها ضمن العنصر <code>&lt;script&gt;</code> بالشكل الصحيح، لكنها لن تفعل شيئًا بنفسها.
</p>

<ol>
	<li>
		جرّب أن تضيف السطر التالي تحت الدالة في الشيفرة:
	</li>
</ol>

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

<p>
	يستدعي هذا السطر الدالة وينفذها مباشرة. فعندما تحفظ التغييرات وتعيد تحميل الصفحة، يعرض المتصفح الشيفرة في الصفحة مباشرة ولمرة واحدة، لأننا استدعيناها مرة واحدة.
</p>

<ol start="2">
	<li>
		<p>
			افتح أدوات مطوري ويب في نتصفح وانتقل إلى طرفية جافا سكريبت واكتب السطر السابق مجددًا وسترى كيف تظهر الرسالة مجددًا! حققنا إذا ما نريده وهي دالة يمكن استخدامها بشكل متكرر في أي وقت نشاء. لكن لربما من اﻷفضل استخدامها كاستجابة لحدث ما أو إجراء ما، وهذا ما يحدث في التطبيقات الواقعية، فصندوق الرسائل يظهر مثلًا كاستجابة لوجود بيانات جديدة أو وقوع خطأ ما، أو تنبيه لفعل ما كأن يحاول المستخدم حذف ملفه مثلًا فتكون الرسالة على الشكل "هل أنت متأكد من ذلك؟"، أو عندما يضيف المستخدم بنجاح جهة اتصال جديدة وهكذا. أما في مثالنا، سنعرض الرسالة عندما ينقر المستخدم على الزر.
		</p>
	</li>
	<li>
		<p>
			احذف السطر اﻷخير الذي أضفته إلى الشيفرة.
		</p>
	</li>
	<li>
		<p>
			ما سنفعله تاليًا هو اختيار الزر ثم حفظ مرجع إليه ضمن ثابت، لهذا أَضف الشيفرة التالية أعلى تعريف الدالة:
		</p>
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_25" 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></pre>

<ol start="5">
	<li>
		أضف السطر التالي بعد السطر السابق:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_27" style=""><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"> displayMessage</span><span class="pun">);</span></pre>

<p>
	وعلى غرار ما فعلناه للتعامل مع حدث النقر على زر اﻹغلاق <code>closeBtn</code> نستدعي في هذا السطر الشيفرة كاستجابة لحدث النقر على الزر، لكن بدلًا من استدعاء دالة غير مسماة سنستدعي الدالة التي أنشأناها <code>()displayMessage</code> باسمها.
</p>

<ol start="6">
	<li>
		احفظ التغييرات وأعد تحميل الصفحة، سترى اﻵن الرسالة فقط عندما تنقر على الزر.
	</li>
</ol>

<p>
	قد تتسائل لماذا لم نضع القوسين بعد اسم الدالة عندما نراها كمعامل لدالة ترصد الأحداث؟ السبب هو أننا لا نريد تنفيذ الدالة دون النقر على الزر. فلو غيرت الشيفرة لتصبح على الشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_29" style=""><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"> displayMessage</span><span class="pun">());</span></pre>

<p>
	ثم حفظت التغيرات وأعدت تحميل الصفحة، ستظهر الرسالة مباشرة دون النقر على الزر.
</p>

<p>
	تُدعى اﻷقواس أحيانًا وفق هذا السياق "عامل تنفيذ الدالة function invocation operator"، وتسُستخدم عندما تريد تنفيذ الدالة مباشرة ضمن نطاق العمل الحالي. بالمقابل، لا تُنفّذ الشيفرة داخل الدالة غير المسماة مباشرة، لأنها ضمن نطاق الدالة التي تترصد الحدث.
</p>

<p>
	تراجع عن التغيرات السابقة إن جربت الفكرة السابقة قبل المتابعة.
</p>

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

<p>
	لا زالت الدالة بشكلها الحالي غير مفيدة، فلا نريد عرض نفس الرسالة دائمًا، لهذا سنحاول تحسين الدالة بإضافة معاملات تسمح لنا باستدعائها وفق عدة خيارات:
</p>

<ol>
	<li>
		عدّل بداية السطر اﻷول من الدالة ليصبح كالتالي:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_31" style=""><span class="kwd">function</span><span class="pln"> displayMessage</span><span class="pun">(</span><span class="pln">msgText</span><span class="pun">,</span><span class="pln"> msgType</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	عندما نستدعي الدالة اﻵن، يمكننا تزويدها بمتغيرين ضمن القوسين لتحديد الرسالة التي تعرضها في صندوق الرسائل ونوع هذه الرسالة.
</p>

<ol start="2">
	<li>
		للاستفادة من المعامل اﻷول، عدّل السطر التالي:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_33" style=""><span class="pln">msg</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"This is a message box"</span><span class="pun">;</span></pre>

<p>
	ليصبح بالشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_39" style=""><span class="pln">msg</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> msgText</span><span class="pun">;</span></pre>

<ol start="3">
	<li>
		عليك اﻵن تعديل استدعاء الدالة لتضم نص الرسالة الجديد، لهذا عدّل السطر التالي:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_35" style=""><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"> displayMessage</span><span class="pun">);</span></pre>

<p>
	ليصبح بالشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_37" style=""><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">
  displayMessage</span><span class="pun">(</span><span class="str">"Woo, this is a different message!"</span><span class="pun">),</span><span class="pln">
</span><span class="pun">);</span></pre>

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

<ol start="4">
	<li>
		أعد تحميل الصفحة مجددًا وسترى أنها لا تزال تعمل جيدًا، ما عدا أنك تستطيع تغيير الرسالة الموجودة ضمن المعامل لتعرض رسالة مختلفة في صندوق الرسائل.
	</li>
</ol>

<h3 id="-5">
	معامل أكثر تعقيدًا
</h3>

<p>
	بالنسبة للمعامل اﻵخر، سيتطلب اﻷمر عملًا أكثر. إذ سنجعل صندوق الرسائل يعرض أيقونة مختلفة وخلفية ذات لون مختلف وفقًا لقيمة هذا المعامل (<code>msgType</code>).
</p>

<ol>
	<li>
		حمّل اولاً اﻷيقونات اللازمة لهذا التمرين (أيقونة <a href="https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/functions/icons/warning.png" rel="external nofollow">التحذير</a> وأيقونة <a href="https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/functions/icons/chat.png" rel="external nofollow">المحادثة</a>) ثم خزنهما في المجلد "icons".
	</li>
	<li>
		ابحث عن تنسيقات CSS داخل الملف لأننا سنجري بعض التغييرات لعرض اﻷيقونات، ثم عدّل اتساع صندوق الرسائل من <code>width: 200px</code> إلى <code>width: 242px</code>.
	</li>
	<li>
		أضف الشيفرة التالية داخل القاعدة <code>{} msgBox p.</code>:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_41" style=""><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">82px</span><span class="pun">;</span><span class="pln">
background</span><span class="pun">-</span><span class="pln">position</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25px</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
background</span><span class="pun">-</span><span class="pln">repeat</span><span class="pun">:</span><span class="pln"> no</span><span class="pun">-</span><span class="pln">repeat</span><span class="pun">;</span></pre>

<ol start="4">
	<li>
		سنضيف اﻵن بعض الشيفرة إلى الدالة <code>()displayMessage</code> لعرض اﻷيقونات بالشكل المطلوب. لهذا ضع الشيفرة التالية داخل القوسين المعقوصين للدالة:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_43" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">msgType </span><span class="pun">===</span><span class="pln"> </span><span class="str">"warning"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  msg</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">backgroundImage </span><span class="pun">=</span><span class="pln"> </span><span class="str">"url(icons/warning.png)"</span><span class="pun">;</span><span class="pln">
  panel</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="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">msgType </span><span class="pun">===</span><span class="pln"> </span><span class="str">"chat"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  msg</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">backgroundImage </span><span class="pun">=</span><span class="pln"> </span><span class="str">"url(icons/chat.png)"</span><span class="pun">;</span><span class="pln">
  panel</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">"aqua"</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">
  msg</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">paddingLeft </span><span class="pun">=</span><span class="pln"> </span><span class="str">"20px"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إن كانت قيمة العامل <code>msgBox</code>  هي <code>warning</code> ستُعرض أيقونة التحذير وتصبح لون خلفية صندوق الرسائل أحمر، وإن كانت قيمته <code>chat</code> ستُعرض أيقونة المحادثة ويصبح لون الخلفية أزرق مائي. إما إن لم تُضبط قيمة المعامل <code>msgType</code> أو أسندت إليه قيمة غير محددة، ستُنفَّذ الشيفرة داخل <code>{}else</code> وستأخذ الفقرة النصية الحاشية الافتراضية ولن تظهر اﻷيقونة ولن يُضبط لون الخلفية، وبهذا يكون هذا المعامل اختياريًا.
</p>

<ol start="5">
	<li>
		لنجرّب اﻵن الشكل المعدّل للدالة <code>()displayMessage</code> ونغيّر طريقة الاستدعاء من الشكل:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_45" style=""><span class="pln">displayMessage</span><span class="pun">(</span><span class="str">"Woo, this is a different message!"</span><span class="pun">);</span></pre>

<p>
	لتصبح كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8270_47" style=""><span class="pln">displayMessage</span><span class="pun">(</span><span class="str">"Your inbox is almost full — delete some mails"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"warning"</span><span class="pun">);</span><span class="pln">
displayMessage</span><span class="pun">(</span><span class="str">"Brian: Hi there, how are you today?"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"chat"</span><span class="pun">);</span></pre>

<p>
	لاحظ فائدة المعاملات في تحسين طريقة عمل الدوال.
</p>

<p>
	<strong>ملاحظة</strong>: إن لم تعمل الشيفرة أو واجهتك المشاكل، بإمكانك موازنة شيفرتك مع <a href="https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/functions/function-stage-4.html" rel="external nofollow">الشيفرة الجاهزة على جت-هب</a> (أو <a href="https://mdn.github.io/learning-area/javascript/building-blocks/functions/function-stage-4.html" rel="external nofollow">تجريها مباشرة</a>) أو طرح أية أسئلة في قسم التعليقات أسفل المقال أو في قسم الأسئلة والأجوبة في أكاديمية حسوب.
</p>
<iframe width="873" height="491" src="https://academy.hsoub.com/applications/core/interface/index.html" title="ماذا يمكنك أن تفعل مع لغة JavaScript" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen data-embed-src="https://www.youtube.com/embed/13wL3IMDaHo"></iframe>

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

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

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

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

<ul>
	<li>
		المقال السابق:<a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AF%D9%88%D8%A7%D9%84-%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%83-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2293/" rel="">الدوال وإعادة استخدام الشيفرة في جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r620/" rel="">الدوال Functions في جافاسكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B9%D9%84%D9%8A%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1242/" 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>
</ul>
]]></description><guid isPermaLink="false">2293</guid><pubDate>Sat, 06 Apr 2024 12:08:04 +0000</pubDate></item><item><title>&#x627;&#x644;&#x639;&#x645;&#x644;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x631;&#x64A;&#x627;&#x636;&#x64A;&#x629; &#x639;&#x644;&#x649; &#x627;&#xFEF7;&#x639;&#x62F;&#x627;&#x62F; &#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%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B1%D9%8A%D8%A7%D8%B6%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%A7%EF%BB%B7%D8%B9%D8%AF%D8%A7%D8%AF-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2289/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_04/-----.png.b5fe4713822ae9da14a29a2465120ba0.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>
</ol>

<h2 id="-1">
	الرياضيات للجميع
</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>. فالكثير من اﻷمور التي ننفذها في <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A3%D9%83%D9%88%D8%A7%D8%AF-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r2244/" rel="">أكواد البرمجة</a> تعتمد على معالجة بيانات عددية، أو حساب قيم جديدة. لهذا لا تتفاجأ إن علمت أن لغة جافا سكريبت تضم مجموعة متكاملة من الدوال الرياضية الجاهزة للاستخدام. وما نقدمه في هذا المقال مجرد تعريف بالميزات اﻷساسية التي لا بد من معرفتها.
</p>

<h3 id="-2">
	أنواع اﻷعداد
</h3>

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

<ul>
	<li>
		<strong>الأعداد الصحيحة Integers:</strong> وهي أعداد ذات فاصلة عائمة لكن دون أجزاء عشرية (لا أرقام بعد الفاصلة) قد تكون موجبة أو سالبة مثل "34" أو "5-".
	</li>
	<li>
		<strong>اﻷعداد ذات الفاصلة العائمة Floating point numbers:</strong>ولها خانات عشرية وأجزاء عشرية (تضم أرقام بعد الفاصلة) مثل "12.5" و "23.3331".
	</li>
	<li>
		<strong>اﻷعداد المضاعفة Doubles:</strong> تمثل نمطًا خاصًا من اﻷعداد العائمة لكنها تمتلك دقة أكبر من اﻷعداد ذات الفاصلة العائمة المعيارية (أي أنها تمثل القيم ذات اﻷجزاء العشرية بدقة أكبر إذ تضم عددًا أكبر من اﻷرقام بعد الفاصلة). كما يوجد أكثر من نظام عد، فالنظام العشري هو نظام أساسه العدد 10 (أي يتكون أي عدد وفق النظام العشري من خانات مكوّنة من أرقام بين 0 إلى 9)، لكن هناك أنظمة أخرى مثل:
	</li>
	<li>
		<strong>النظام الثنائي Binary:</strong> يستخدم في لغات البرمجة منخفضة المستوى وتتكون أعداده من تتابع رقمين فقط 0 أو 1.
	</li>
	<li>
		<strong>النظام الثماني Octal:</strong> أساسه 8 أي يستخدم فقط اﻷرقام من 0 إلى 7.
	</li>
	<li>
		<strong>النظام الست عشري hexadecimal:</strong> أساسه 16 ويستخدم اﻷرقام من 0 إلى 9 والحروف من a إلى f (ربما اطلعت على هذا النظام عند ضبط اﻷلوان في CSS). لكننا كبداية سنلتزم بنظام العد العشري المألوف بالنسب لك خلال سلسلة مقالاتنا التمهيدية هذه، ولن تكون مضطرًا للتفكير ببقية اﻷنظمة. أما الخبر الجيد التالي فهو أن جافا سكريبت تعرّف نوعًا واحدًا للبيانات العددية هو <code>number</code> على عكس لغات برمجة أخرى فاﻷعداد الصحيحة والعائمة والمضاعفة هي مجرد أعداد في جافا سكريبت وتتعامل معها بنفس الطريقة تمامًا.
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: في الواقع هناك نوع آخر للأعداد في جافا سكريبت غير <code>number</code> وهو النوع <code>BigInt</code> وهو يستخدم للتعامل مع اﻷعداد الضخمة جدًا، لكننا لن نستخدمه في سلسلتنا هذه.
</p>

<h3 id="-3">
	كلها أعداد بالنسبة لجافا سكريبت
</h3>

<p>
	سنجرّب العمل مع بعض اﻷعداد حتى نتعرف على الصياغة الصحيحة، لهذا ادخل إلى طرفية جافا سكريبت في متصفحك (اضغط "Ctrl" + "Shift" + "K" في متصفح فايرفوكس) واتبع الخطوات التالية:
</p>

<ol>
	<li>
		صرّح عن المتغيرين التاليين <code>myInt</code> و <code>myFloat</code> (ثابتين باﻷحرى) على الترتيب ثم اكتبهما في الطرفية من جديد للتأكد أن كل شيء على ما يرام:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_15" style=""><span class="pln">   </span><span class="kwd">const</span><span class="pln"> myInt </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">const</span><span class="pln"> myFloat </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6.667</span><span class="pun">;</span><span class="pln">
   myInt</span><span class="pun">;</span><span class="pln">
   myFloat</span><span class="pun">;</span></pre>

<ol start="2">
	<li>
		تُسند القيم العددية للمتغيرات دون أن تُحاط بإشارات تنصيص.
	</li>
	<li>
		تحقق اﻵن أن المتغيران لهما نفس النوع باستخدام العامل <code>typeof</code> يليها اسم المتغير كالتالي:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_17" style=""><span class="pln">   </span><span class="kwd">typeof</span><span class="pln"> myInt</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">typeof</span><span class="pln"> myFloat</span><span class="pun">;</span></pre>

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

<h3 id="-4">
	توابع رياضية مفيدة
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_20" style=""><span class="kwd">const</span><span class="pln"> lotsOfDecimal </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1.766584958675746364</span><span class="pun">;</span><span class="pln">
lotsOfDecimal</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> twoDecimalPlaces </span><span class="pun">=</span><span class="pln"> lotsOfDecimal</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">
twoDecimalPlaces</span><span class="pun">;</span></pre>

<h3 id="number">
	التحويل إلى النوع <code>number</code>
</h3>

<p>
	قد ينتهي بنا اﻷمر أحيانًا إلى مواجهة عدد مخزّن ضمن سلسلة نصية ومن الصعب حينها تنفيذ أية حسابات رياضية عليه. وعادة ما نواجه هذه الحالات عند استخلاص البيانات الموجودة في حقل إدخال نصي <code>&lt;input&gt;</code> ضمن نموذج <code>&lt;form&gt;</code>. وبالطبع هناك طريقة لحل هه المشكلة تتمثل في تمرير هذه القيمة إلى الكائن <code>()Number</code> الذي يعيد نفس القيمة لكن كعدد وليس كسلسلة نصية. لفهم هذه الطريقة جرّب كتابة اﻷسطر التالية في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_22" style=""><span class="kwd">let</span><span class="pln"> myNumber </span><span class="pun">=</span><span class="pln"> </span><span class="str">"74"</span><span class="pun">;</span><span class="pln">
myNumber </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span></pre>

<p>
	ستلاحظ أن الجواب سيكون 743 بدلًا من 77، ذلك أن <code>myNumber</code> يعرف في الواقع سلسلة نصية. وللتأكد من ذلك جرّب ما يلي:
</p>

<pre class="ipsCode">typeof myNumber;
</pre>

<p>
	لاحظ ماذا فعلنا لحل المشكلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_24" style=""><span class="kwd">let</span><span class="pln"> myNumber </span><span class="pun">=</span><span class="pln"> </span><span class="str">"74"</span><span class="pun">;</span><span class="pln">
myNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">myNumber</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span></pre>

<p>
	سنحصل اﻻن على النتيجة المطلوبة 77.
</p>

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

<p>
	وهي العوامل الحسابية اﻷساسية التي تستخدم لتنفيذ الحسابات اﻷساسية كالجمع والطرح وغيرها:
</p>

<table>
	<thead>
		<tr>
			<th style="text-align:center;">
				العامل
			</th>
			<th style="text-align:center;">
				اسمه
			</th>
			<th style="text-align:center;">
				الغاية منه
			</th>
			<th style="text-align:center;">
				مثال
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:center;">
				<code>+</code>
			</td>
			<td style="text-align:center;">
				الجمع
			</td>
			<td style="text-align:center;">
				إضافة عددين إلى بعضهما
			</td>
			<td style="text-align:center;">
				<code>6+9</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:center;">
				<code>-</code>
			</td>
			<td style="text-align:center;">
				الطرح
			</td>
			<td style="text-align:center;">
				طرح العدد اﻷيمن من اﻷيسر
			</td>
			<td style="text-align:center;">
				<code>6-9</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:center;">
				<code>*</code>
			</td>
			<td style="text-align:center;">
				الضرب
			</td>
			<td style="text-align:center;">
				ضرب عددين معًا
			</td>
			<td style="text-align:center;">
				<code>9*6</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:center;">
				<code>/</code>
			</td>
			<td style="text-align:center;">
				القسمة
			</td>
			<td style="text-align:center;">
				قسمة العدد اﻷيسر على اﻷيمن
			</td>
			<td style="text-align:center;">
				<code>9/6</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:center;">
				<code>%</code>
			</td>
			<td style="text-align:center;">
				باقي القسمة
			</td>
			<td style="text-align:center;">
				يعيد باقي قسمة العدد اﻷيسر على اﻷيمن
			</td>
			<td style="text-align:center;">
				<code>4%9</code> سيكون الناتج هو 1
			</td>
		</tr>
		<tr>
			<td style="text-align:center;">
				<code>**</code>
			</td>
			<td style="text-align:center;">
				الرفع إلى قوة
			</td>
			<td style="text-align:center;">
				يرفع العدد اﻷيمن إلى قوة هي العدد اﻷيسر
			</td>
			<td style="text-align:center;">
				<code>4**2</code> سيكون الناتج هو 16
			</td>
		</tr>
	</tbody>
</table>

<p>
	<strong>ملاحظة1:</strong> تُدعى اﻷعداد التي تخضع للعمليات الحسابية بالمعاملات operands.
</p>

<p>
	<strong>ملاحظة2:</strong> قد ترى أحيانًا عملية رفع إلى قوة باستخدام التابع اﻷقدم <code>()Math.pow</code> الذي يعمل بنفس الطريقة فالأمر <code>(7,3)Math.pow</code> يعطي نفس نتيجة الأمر <code>3**7</code>. لن نعلّمك بالطبع كيف تجري الحسابات الرياضية لكن نريد اختبار فهمك لصياغة هذه العمليات باستخدام جافا سكريبت، لهذا افتح طرفية المتصفح واتبع الخطوات التالية:
</p>

<ol>
	<li>
		حاول بداية أن تنفذ بعض العمليات التي تختارها مثل:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_26" style=""><span class="pln">   </span><span class="lit">10</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">7</span><span class="pun">;</span><span class="pln">
   </span><span class="lit">9</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">8</span><span class="pun">;</span><span class="pln">
   </span><span class="lit">60</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span></pre>

<ol start="2">
	<li>
		بإمكانك أيضًا أن تجرب تصريح وتهيئة بعض المتغيرات بقيم عددية من اختيارك، ثم حاول استخدام هذه المتغيرات لتنفيذ عمليات حسابية، إذ ستسلك المتغيرات سلوك قيمها تمامًا. إليك بعض اﻷمثلة:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_28" style=""><span class="pln">   </span><span class="kwd">const</span><span class="pln"> num1 </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">const</span><span class="pln"> num2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">50</span><span class="pun">;</span><span class="pln">
   </span><span class="lit">9</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> num1</span><span class="pun">;</span><span class="pln">
   num1 </span><span class="pun">**</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
   num2 </span><span class="pun">/</span><span class="pln"> num1</span><span class="pun">;</span></pre>

<ol start="3">
	<li>
		حاول أخيرًا أن تختبر بعض العبارات اﻷكثر تعقيدًا مثل:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_30" style=""><span class="pln">   </span><span class="lit">5</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">3</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">(</span><span class="pln">num2 </span><span class="pun">%</span><span class="pln"> </span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> num1</span><span class="pun">;</span><span class="pln">
   num2 </span><span class="pun">+</span><span class="pln"> num1 </span><span class="pun">/</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span></pre>

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

<h3 id="-6">
	أفضلية العمليات الحسابية
</h3>

<p>
	لنلق نظرة على المثال السابق ولنفترض أن المتغير <code>num2</code> يضم القيمة 50 ويضم المتغير <code>num1</code> القيمة 10 ولننفذ العملية التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_32" style=""><span class="pln">num2 </span><span class="pun">+</span><span class="pln"> num1 </span><span class="pun">/</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span></pre>

<p>
	فقد يقرأ البعض هذه العملية بالشكل 50 زائد 10 يساوي 60 ثم * 8 زائد 2 يساوي 10 وأخيرًا 60 تقسيم 10 يساوي 6. لكن ما يفعله المتصفح هو التالي 10 تقسيم 8 يساوي 1.25 ثم 50 زائد 1.25 زائد 2 يساوي 53.25.
</p>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_34" style=""><span class="pun">(</span><span class="pln">num2 </span><span class="pun">+</span><span class="pln"> num1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="lit">8</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span></pre>

<p>
	جرب ذلك وسترى!
</p>

<h2 id="-7">
	عوامل الزيادة والنقصان
</h2>

<p>
	قد تتطلب الحسابات أحيانًا إضافة نفس العدد أو طرحه بشكل مستمر من متغير عددي. يمكن أن ننجز ذلك مباشرة باستخدام العامل (<code>++</code>) للزيادة بواحد و (<code>--</code>) للإنقاص بواحد. وتذكر أننا استخدمنا العامل (<code>++</code>) في لعبة "خمّن الرقم" في مقال سابق. حيث زدنا قيمة المتغير بمقدار واحد لتتبع عدد المحاولات التي نفّذها اللاعب.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_38" style=""><span class="pln">guessCount</span><span class="pun">++;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_40" style=""><span class="lit">3</span><span class="pun">++;</span></pre>

<p>
	لهذا لا يمكن استخدام عامل الزيادة أو النقصان إلا مع المتغيرات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_42" style=""><span class="kwd">let</span><span class="pln"> num1 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4</span><span class="pun">;</span><span class="pln">
num1</span><span class="pun">++;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_44" style=""><span class="pln">num1</span><span class="pun">;</span></pre>

<p>
	ينطبق اﻷمر أيضًا على عامل اﻹنقاص بواحد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_46" style=""><span class="kwd">let</span><span class="pln"> num2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</span><span class="pun">;</span><span class="pln">
num2</span><span class="pun">--;</span><span class="pln">
num2</span><span class="pun">;</span></pre>

<p>
	<strong>ملاحظة:</strong> بإمكانك إضافة أو إنقاص قيمة المتغير ثم عرض النتيجة بوضع عامل الزيادة أو النقصان قبل المتغير مثل <code>num1++</code>. جرّب ذلك!
</p>

<h2 id="-8">
	عوامل اﻹسناد
</h2>

<p>
	وهي عوامل تسند قيمًا إلى المتغيرات وقد استخدمنا منها العامل اﻷساسي <code>=</code> كثيرًا حتى اﻵن، والذي يخزّن القيمة التي على يسار المساواة في المتغير الذي يقع إلى يسارها.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_48" style=""><span class="kwd">let</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln"> </span><span class="com">//القيمة 3 x يضم المتغير </span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4</span><span class="pun">;</span><span class="pln"> </span><span class="com">//القيمة 4 y يضم المتغير</span><span class="pln">
x </span><span class="pun">=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln"> </span><span class="com">//وهي 4 y قيمة المتغير x يتضمن المتغير </span></pre>

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

<table>
	<thead>
		<tr>
			<th style="text-align:left;">
				العامل
			</th>
			<th style="text-align:left;">
				اسمه
			</th>
			<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;">
				جمع قيمة المتغير إلى اليسار مع القيمة على اليمين وإسناد الناتج إلى المتغير ويعيد قيمته الجديدة
			</td>
			<td style="text-align:left;">
				<code>;x+=4;</code>
			</td>
			<td style="text-align:left;">
				<code>x=x+4</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>-=</code>
			</td>
			<td style="text-align:left;">
				إسناد وطرح
			</td>
			<td style="text-align:left;">
				طرح القيمة إلى اليمين من قيمة المتغير على اليسار وإسناد الناتج إلى المتغير ويعيد قيمته الجديدة
			</td>
			<td style="text-align:left;">
				<code>;x-=4;</code>
			</td>
			<td style="text-align:left;">
				<code>x=x-4</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>*=</code>
			</td>
			<td style="text-align:left;">
				إسناد وجداء
			</td>
			<td style="text-align:left;">
				جداء قيمة المتغير إلى اليسار مع القيمة على اليمين وإسناد الناتج إلى المتغير ويعيد قيمته الجديدة
			</td>
			<td style="text-align:left;">
				<code>;x*=4;</code>
			</td>
			<td style="text-align:left;">
				<code>x=x*4</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>/=</code>
			</td>
			<td style="text-align:left;">
				إسناد وقسمة
			</td>
			<td style="text-align:left;">
				تقسيم قيمة المتغير إلى اليسار على القيمة على اليمين وإسناد الناتج إلى المتغير ويعيد قيمته الجديدة
			</td>
			<td style="text-align:left;">
				<code>;x/=4;</code>
			</td>
			<td style="text-align:left;">
				<code>x=x/4</code>
			</td>
		</tr>
	</tbody>
</table>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_50" style=""><span class="kwd">let</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln"> </span><span class="com">//القيمة 3 x يضم المتغير </span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4</span><span class="pun">;</span><span class="pln"> </span><span class="com">//القيمة 4 y يضم المتغير</span><span class="pln">
x </span><span class="pun">*=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln"> </span><span class="com">// القيمة 12 x يتضمن المتغير </span></pre>

<h2 id="-9">
	تطبيق عملي: تحديد أبعاد صندوق رسم
</h2>

<p>
	سنتعامل في هذا التطبيق مع عوامل حسابية ومعاملات مختلفة لتغيير أبعاد صندوق. يُرسم الصندوق باستخدام واجهة برمجية <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> تُدعى <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" rel="external nofollow">Canvas <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a>. لا تقلق حاليًا حيال عمل الواجهة وركّز على الرياضيات. يُعرّف اتساع وارتفاع الصندوق عبر المتغيرين <code>x</code>و <code>y</code> وتقدر قيمتهما بالبكسل ويعطى كلاهما القيمة 50 في البداية.
</p>

<p>
	<iframe height="560" loading="lazy" src="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/maths/editable_canvas.html" 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="100%"></iframe>
</p>

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

<ul>
	<li>
		غير السطر الذي يحسب قيمة x كي يبقى اتساع الصندوق 50 بكسل، لكن يجب أن تُحسب القيمة 50 انطلاقًا من عددين هما 43 و 7 وباستخدام عملية حسابية.
	</li>
	<li>
		غير السطر الذي يحسب قيمة y كي يصبح ارتفاع الصندوق 75 بكسل، لكن يجب أن تُحسب القيمة 75 انطلاقًا من عددين هما 3 و 25 وباستخدام عملية حسابية.
	</li>
	<li>
		غير السطر الذي يحسب قيمة x كي يصبح اتساع الصندوق 250 بكسل، لكن يجب أن تُحسب القيمة 250 انطلاقًا من عددين وعملية باقي القسمة.
	</li>
	<li>
		غير السطر الذي يحسب قيمة y كي يصبح ارتفاع الصندوق 150 بكسل، لكن يجب أن تُحسب القيمة 150 انطلاقًا من ثلاثة أعداد وعمليتي طرح وقسمة.
	</li>
	<li>
		غير السطر الذي يحسب قيمة x كي يصبح اتساع الصندوق 200 بكسل، لكن يجب أن تُحسب القيمة 250 انطلاقًا من العدد 4 وعامل إسناد.
	</li>
	<li>
		غير السطر الذي يحسب قيمة y كي يصبح ارتفاع الصندوق 200 بكسل، لكن يجب أن تُحسب القيمة 250 انطلاقًا من العددين 50 و 3 وعمل الضرب وعامل اﻹسناد واﻹضافة.
	</li>
</ul>

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

<h2 id="-10">
	عوامل الموازنة
</h2>

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

<table>
	<thead>
		<tr>
			<th style="text-align:left;">
				العامل
			</th>
			<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;">
				يختبر إن كان القيمتين على يسار ويمين العامل متطابقتين تمامًا
			</td>
			<td style="text-align:left;">
				<code>4+3==5</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>==!</code>
			</td>
			<td style="text-align:left;">
				لا مساواة تامة
			</td>
			<td style="text-align:left;">
				يختبر إن كان القيمتين على يسار ويمين العامل غير متطابقتين تمامًا
			</td>
			<td style="text-align:left;">
				<code>2+3=!5</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>&gt;</code>
			</td>
			<td style="text-align:left;">
				أصغر من
			</td>
			<td style="text-align:left;">
				يختبر إن كانت القيمة على يمين العامل أصغر تمامًا من القيمة إلى يساره
			</td>
			<td style="text-align:left;">
				<code>10&lt;6</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>&lt;</code>
			</td>
			<td style="text-align:left;">
				أكبر من
			</td>
			<td style="text-align:left;">
				يختبر إن كانت القيمة على يمين العامل أكبر تمامًا من القيمة إلى يساره
			</td>
			<td style="text-align:left;">
				<code>6&gt;10</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>=&gt;</code>
			</td>
			<td style="text-align:left;">
				أصغر من أو يساوي
			</td>
			<td style="text-align:left;">
				يختبر إن كانت القيمة على يمين العامل أصغر أو تساوي القيمة إلى يساره
			</td>
			<td style="text-align:left;">
				<code>3=&gt;2</code>
			</td>
		</tr>
		<tr>
			<td style="text-align:left;">
				<code>=&gt;</code>
			</td>
			<td style="text-align:left;">
				أكبر من أو يساوي
			</td>
			<td style="text-align:left;">
				يختبر إن كانت القيمة على يمين العامل أكبر أو تساوي من القيمة إلى يساره
			</td>
			<td style="text-align:left;">
				<code>3=&lt;2</code>
			</td>
		</tr>
	</tbody>
</table>

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

<p>
	إن حاولت تجريب بعض القيم السابقة في الطرفية سيكون الناتج إما <code>true</code> أو <code>false</code> وهي القيم المنطقية booleans التي ذكرناها في <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-%D9%88%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%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2287/" rel="">المقال السابق</a>. ولهذه القيم الكثير من الفوائد فهي تسمح باتخاذ القرارات في شيفرتنا، إذ تُستخدم في كل مرة تحتاج فيها إلى اتخاذ قرار ما. ويمكن استخدام القيم المنطقي على سبيل المثال في:
</p>

<ul>
	<li>
		إظهار العنوان المناسب على زر وذلك إن كانت ميزة ما مفعّلة أو معطّلة.
	</li>
	<li>
		إظهار رسالة "انتهت اللعبة" عندما تنتهي أو رسالة فوز إن ربح اللاعب.
	</li>
	<li>
		عرض التحية المناسبة وفقًا لموسم العطلات.
	</li>
	<li>
		تقريب الخريطة وفقًا لمستوى التقريب الذي تختاره. سنرى لاحقًا كيفية كتابة منطق الاستخدامات السابقة عند المرور على العبارات الشرطية لاحقًا، لكن لا بد أن نلق نظرة اﻵن على مثال سريع:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4503_53" style=""><span class="tag">&lt;button&gt;</span><span class="pln">Start machine</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;p&gt;</span><span class="pln">The machine is stopped.</span><span class="tag">&lt;/p&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4503_55" 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"> txt </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">

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"> updateBtn</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> updateBtn</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">btn</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">===</span><span class="pln"> </span><span class="str">"Start machine"</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">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Stop machine"</span><span class="pun">;</span><span class="pln">
    txt</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"The machine has started!"</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">
    btn</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Start machine"</span><span class="pun">;</span><span class="pln">
    txt</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> </span><span class="str">"The machine is stopped."</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<iframe height="100" loading="lazy" src="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/maths/conditional.html" 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="100%"></iframe>
</p>

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

<p>
	<strong>ملاحظة</strong>: يُشار عادة إلى عملية التبديل تلك باسم "الانتقال toggle".
</p>

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

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

<p>
	ترجمة -وبتصرف- لمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Math" rel="external nofollow">Basic math in JavaScript-Numbers and Operators</a>
</p>

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

<ul>
	<li>
		المقال السابق: <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-%D9%88%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%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2287/" rel="">المتغيرات وتخزين البيانات في جافا سكريبت</a>
	</li>
	<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/%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/" 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>
</ul>
]]></description><guid isPermaLink="false">2289</guid><pubDate>Tue, 02 Apr 2024 12:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x62A;&#x63A;&#x64A;&#x631;&#x627;&#x62A; &#x648;&#x62A;&#x62E;&#x632;&#x64A;&#x646; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#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%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%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%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r2287/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_03/----.png.35f5c0ee1d5ddca4d8945dce6cee1002.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>
</ol>

<h2 id="-1">
	الأدوات التي تحتاجها
</h2>

<p>
	سنطلب إليك مع تقدم مقالنا كتابة بعض أسطر الشيفرة لنختر فهمك لما شرحناه. فإن كنت تستخدم متصفح حاسوب مكتبي، ستجد أن أفضل مكان لكتابة الشيفرة هو طرفية جافا سكريبت في المتصفح Web Console التي تمكّنك من التفاعل مع صفحة الويب عن طريق تنفيذ تعبيرات جافا سكريبت في سياق الصفحة (اضغط اﻷزرار "Ctrl" + "Shift" + "K" معًا لفتحها في متصفح فايرفوكس).
</p>

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

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

<h3 id="-3">
	أمثلة عن المتغيرات
</h3>

<p>
	لنلق نظرة على هذا المثال البسيط:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5834_7" style=""><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"button_A"</span><span class="tag">&gt;</span><span class="pln">Press me</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;h3</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"heading_A"</span><span class="tag">&gt;&lt;/h3&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_9" style=""><span class="kwd">const</span><span class="pln"> buttonA </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_A"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> headingA </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">"#heading_A"</span><span class="pun">);</span><span class="pln">

buttonA</span><span class="pun">.</span><span class="pln">onclick </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"> name </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"What is your name?"</span><span class="pun">);</span><span class="pln">
  alert</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><span class="pln"> nice to see you</span><span class="pun">!`);</span><span class="pln">
  headingA</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">Welcome</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="200" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/abxJboB?default-tab=result" style="width: 100%;" title="js-variables 1">See the Pen js-variables 1 by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

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

<h3 id="-4">
	كيف سيكون الوضع دون متغيّرات؟
</h3>

<p>
	لكي نفهم الفائدة الكبيرة من استخدام المتغيرات، دعونا نفكّر بطريقة لكتابة شيفرة المثال السابق دون استعمال المتغيرات. سينتهي بنا اﻷمر إلى شيفرة من هذا القبيل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5834_11" style=""><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"button_B"</span><span class="tag">&gt;</span><span class="pln">Press me</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;h3</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"heading_B"</span><span class="tag">&gt;&lt;/h3&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_13" style=""><span class="kwd">const</span><span class="pln"> buttonB </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_B"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> headingB </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">"#heading_B"</span><span class="pun">);</span><span class="pln">

buttonB</span><span class="pun">.</span><span class="pln">onclick </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="typ">Hello</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">prompt</span><span class="pun">(</span><span class="str">"What is your name?"</span><span class="pun">)},</span><span class="pln"> nice to see you</span><span class="pun">!`);</span><span class="pln">
  headingB</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">Welcome</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">prompt</span><span class="pun">(</span><span class="str">"What is your name?"</span><span class="pun">)}`;</span><span class="pln">
</span><span class="pun">};</span></pre>

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

<p>
	ربما لن تدرك جيدًا الصياغة التي استخدمناها حاليًا، لكن لا بد وأن تكون قد استوعبت الفكرة. فإن لم يكن لديك متغيرات، ستسأل المستخدم كل مرة عن اسمه إن احتجته في الشيفرة. إذًا من المنطقي استخدام المتغيرات، وستألفها مع تقدمك في تعلم جافا سكريبت. ومن المهم أن تعرف أنك قادر على تخزين أي شيء تقريبًا في المتغيرات وليس فقط النصوص والأرقام. فقد تضم المتغيرات بنى مركّبة من البيانات وحتى دالة بأكملها، وهذا ما ستتعلمه خلال <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>. <strong>ملاحظة:</strong> لقد أشرنا أن المتغيرات تضم قيمًا أي أن المتغيرات ليست قيمًا بحد ذاتها بل حاويات للقيم. يمكن أن تشبهها بعلبة من الكرتون تضع اﻷغراض بداخلها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="147106" href="https://academy.hsoub.com/uploads/monthly_2024_03/01_Cardbox_variables.png.da341aa385640eccf3655c983d40c7c9.png" rel=""><img alt="01 cardbox variables" class="ipsImage ipsImage_thumbnailed" data-fileid="147106" data-unique="mjuhix3sx" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2024_03/01_Cardbox_variables.thumb.png.4777cecbd26950475199f57ef8b90317.png"> </a>
</p>

<h2 id="-5">
	التصريح عن المتغيرات
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_16" style=""><span class="kwd">let</span><span class="pln"> myName</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> myAge</span><span class="pun">;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_18" style=""><span class="pln">myName</span><span class="pun">;</span><span class="pln">
myAge</span><span class="pun">;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_20" style=""><span class="pln">name</span><span class="pun">;</span></pre>

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

<h2 id="-6">
	تهيئة المتغيّر
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_22" style=""><span class="pln">myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Chris"</span><span class="pun">;</span><span class="pln">
myAge </span><span class="pun">=</span><span class="pln"> </span><span class="lit">37</span><span class="pun">;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_24" style=""><span class="pln">myName</span><span class="pun">;</span><span class="pln">
myAge</span><span class="pun">;</span></pre>

<p>
	باﻹمكان أيضًا التصريح عن المتغير وتهيئته في نفس الوقت كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_26" style=""><span class="kwd">let</span><span class="pln"> myDog </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Rover"</span><span class="pun">;</span></pre>

<p>
	وهذا ما ستفعله غالبًا لأنها طريقة أسرع.
</p>

<h2 id="-7">
	ملاحظة حول المتغيرات
</h2>

<p>
	قد تصادف أيضًا طريقة مختلفة في التصريح عن المتغيرات وذلك باستخدام التعليمة <a href="https://wiki.hsoub.com/JavaScript/var" rel="external"><code>var</code></a> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_28" style=""><span class="kwd">var</span><span class="pln"> myName</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> myAge</span><span class="pun">;</span></pre>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_32" style=""><span class="pln">myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Chris"</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"> logName</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">myName</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

logName</span><span class="pun">();</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> myName</span><span class="pun">;</span><span class="pln"> </span><span class="com">//التصريح عن نفس المتحول من جديد</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_34" style=""><span class="kwd">var</span><span class="pln"> myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Chris"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Bob"</span><span class="pun">;</span></pre>

<p>
	لكن الشيفرة التالية ستعطي خطأً في السطر الثاني:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_36" style=""><span class="kwd">let</span><span class="pln"> myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Chris"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Bob"</span><span class="pun">;</span></pre>

<p>
	وعليك أن تعيد كتابة الشيفرة لتصبح بالشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_38" style=""><span class="kwd">let</span><span class="pln"> myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Chris"</span><span class="pun">;</span><span class="pln">
myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Bob"</span><span class="pun">;</span></pre>

<p>
	ونؤكد أن وجود <code>let</code>هو قرار لغوي معقول، فلا معنى لتعريف المتغيرات مرة أخرى لأنها تربك القارئ. لهذه اﻷسباب وغيرها ننصحك باستخدام <code>let</code> في الشيفرة إلا إن كنت ستكتب صراحة شيفرة تدعم المتصفحات القديمة لأن جميع المتصفحات الحديثة تدعمها منذ عام 2015.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_40" style=""><span class="pun">&gt;</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Chris"</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Bob"</span><span class="pun">;</span><span class="pln">
</span><span class="com">// SyntaxError: Identifier 'myName' has already been declared إن أدخلت الشيفرة سطرًا سطرًا: ستحصل على الخطأ</span><span class="pln">

</span><span class="pun">&gt;</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Chris"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&gt;</span><span class="pln"> </span><span class="kwd">let</span><span class="pln"> myName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Bob"</span><span class="pun">;</span><span class="pln">
</span><span class="com">// As two inputs: both succeed إن أدخلتهما معًا ستنجح العملية</span></pre>

<h2 id="-8">
	تحديث متغيّر
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_42" style=""><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Bob"</span><span class="pun">;</span><span class="pln">
myAge </span><span class="pun">=</span><span class="pln"> </span><span class="lit">40</span><span class="pun">;</span></pre>

<h3 id="-9">
	نظرة إلى قواعد تسمية المتغيرات
</h3>

<p>
	يمكنك أن تسمي متغيرك بأي اسم تريد مع وجود بعض القيود. وعمومًا التزم باستخدام المحارف اللاتينية (0-9, a-z, A-Z) ومحرف الشرطة السفلية (<code>_</code>).
</p>

<ul>
	<li>
		لا تستخدم محارف أخرى لأنها قد تسبب أخطاءً أو تجعل الشيفرة صعبة الفهم للقارئين حول العالم.
	</li>
	<li>
		لا تستخدم الشرطة السفلية في بداية اسم المتغيّر لأنه أسلوب مستخدم في بعض بنى جافا سكريبت وله دلالة خاصة.
	</li>
	<li>
		لا تستخدم أرقامًا في بداية الاسم، فهذا غير مسموح ويسبب خطأ.
	</li>
	<li>
		من العادات الآمنة أن تلتزم بحرف صغير في بداية الاسم، وإن أردت ضم عدة كلمات لتعيين اسم المتغير اكتب أحرف الكلمة اﻷولى جمعها بأحرف صغيرة ثم اجعل بدايات الكلمات التالية بأحرف كبيرة. وهذا ما استخدمناه في مقالنا حتى اﻵن.
	</li>
	<li>
		اجعل أسماء المتغيرات واضحة وتصف البيانات التي تخزّنها، ولا تستخدم أحرفًا مفردة أو عبارات طويلة.
	</li>
	<li>
		انتبه إلى أن المتغيرات حساسة لحالة اﻷحرف فالمتغير <code>myAge</code> مختلف عن <code>myage</code>.
	</li>
	<li>
		نقطة أخيرة: تجنب استخدام كلمات جافا سكريبت المحجوزة (التعليمات) كأسماء متغيرات مثل <code>var</code> و <code>function</code> و <code>let</code>و <code>for</code>، فلن يميزها المتصفح كمتغيرات وستظهر اﻷخطاء مباشرة. <strong>ملاحظة:</strong> إليك <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#keywords" rel="external nofollow">قائمة بالكلمات المحجوزة</a> التي لا ينبغي استخدامها كأسماء متغيرات. وإليك بعض اﻷمثلة عن التسمية الجيدة للمتغيرات:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_44" style=""><span class="pln">age
myAge
init
initialColor
finalOutputValue
audio1
audio2</span></pre>

<p>
	وأمثلة عن التسمية السيئة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_46" style=""><span class="lit">1</span><span class="pln">
a
_12
myage
MYAGE
</span><span class="kwd">var</span><span class="pln">
</span><span class="typ">Document</span><span class="pln">
skjfndskjfnbdskjfb
thisisareallylongvariablenameman</span></pre>

<p>
	جرّب أن تسمي بعض المتغيرات وفقًا للنقاط التي ناقشناها سابقًا.
</p>

<h2 id="-10">
	أنواع المتغيرات
</h2>

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

<h3 id="-11">
	اﻷعداد
</h3>

<p>
	بإمكانك تخزين اﻷعداد ضمن المتغيرات كاﻷعداد الصحيحة مثل (30) أو الأعداد العشرية مثل (2.234) وتُدعى أيضًا (أعداد عائمة float أو أعداد ذات فاصلة عائمة). ولا حاجة للتصريح عن نوع المتغير في جافا سكريبت على عكس العديد من لغات البرمجة اﻷخرى. وعندما تُخزّن أعدادًا ضمن المتغير لا داعي لإحاطة العدد بعلامتي تنصيص.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_48" style=""><span class="kwd">let</span><span class="pln"> myAge </span><span class="pun">=</span><span class="pln"> </span><span class="lit">17</span><span class="pun">;</span></pre>

<h3 id="-12">
	النصوص (السلاسل النصية)
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_50" style=""><span class="kwd">let</span><span class="pln"> dolphinGoodbye </span><span class="pun">=</span><span class="pln"> </span><span class="str">"So long and thanks for all the fish"</span><span class="pun">;</span></pre>

<h3 id="-13">
	القيم المنطقية
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_52" style=""><span class="kwd">let</span><span class="pln"> iAmAlive </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span></pre>

<p>
	لكن ما ستراه في الواقع شيفرة كهذه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_54" style=""><span class="kwd">let</span><span class="pln"> test </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span></pre>

<p>
	وقد استخدم العامل (<code>&lt;</code>) لاختبار إن كان الرقم 6 أصغر من 3 ثم خُزنت النتيجة <code>false</code> في المتغيّر. سترى ذلك بتفاصيل أكثر لاحقًا.
</p>

<h3 id="-14">
	المصفوفات
</h3>

<p>
	تُعرّف المصفوفة بأنها كائن في جافا سكريبت يضم عدة قيم تفصل بينها فاصلة <code>,</code> ضمن قوسين مرّبعين <code>[]</code>. جرّب إدخال الأسطر التالية في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_56" style=""><span class="kwd">let</span><span class="pln"> myNameArray </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Chris"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Bob"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jim"</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> myNumberArray </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pun">,</span><span class="pln"> </span><span class="lit">40</span><span class="pun">];</span></pre>

<p>
	بمجرّد أن تعرّف المصفوفات، تستطيع الوصول إلى أي قيمة من القيم المخزنة ضمنها باﻹشارة إلى موقعها. جرّب ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_58" style=""><span class="pln">myNameArray</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln"> </span><span class="com">//'Chris' تعيد  </span><span class="pln">
myNumberArray</span><span class="pun">[</span><span class="lit">2</span><span class="pun">];</span><span class="pln"> </span><span class="com">// 40 تعيد</span></pre>

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

<h3 id="-15">
	الكائنات
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_60" style=""><span class="kwd">let</span><span class="pln"> dog </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="str">"Spot"</span><span class="pun">,</span><span class="pln"> breed</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Dalmatian"</span><span class="pln"> </span><span class="pun">};</span></pre>

<p>
	وكي تسترجع المعلومات المخزنة في كائن، يمكنك استخدام الصياغة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_62" style=""><span class="pln">dog</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span></pre>

<p>
	لن نشرح أكثر عن الكائنات هنا، بل سنترك اﻷمر لمقالات أخرى.
</p>

<h2 id="-16">
	التحديد التلقائي للنوع
</h2>

<p>
	تُحدد جافا سكريبت النوع تلقائيًا dynamically typed language ويعني ذلك أنك لن تحتاج إلى تحديد نوع البيانات التي تخزنها (أعداد، سلاسل نصية، مصفوفات) في متغير على عكس لغات أخرى. فإن صرحت عن متغير وأسندت إليه قيمة ضمن إشارتي تنصيص سيفهم المتصفح أن المتغير هو سلسلة نصية.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_64" style=""><span class="kwd">let</span><span class="pln"> myString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_66" style=""><span class="kwd">let</span><span class="pln"> myNumber </span><span class="pun">=</span><span class="pln"> </span><span class="str">"500"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// المتغير من النوع النصي هنا</span><span class="pln">
</span><span class="kwd">typeof</span><span class="pln"> myNumber</span><span class="pun">;</span><span class="pln">
myNumber </span><span class="pun">=</span><span class="pln"> </span><span class="lit">500</span><span class="pun">;</span><span class="pln"> </span><span class="com">// اﻵن يصبح المتغير عددًا</span><span class="pln">
</span><span class="kwd">typeof</span><span class="pln"> myNumber</span><span class="pun">;</span></pre>

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

<h2 id="-17">
	الثوابت في جافا سكريبت
</h2>

<p>
	يمكن التصريح عن الثوابت constants في جافا سكريبت كما تصرّح عن المتغيرات لكن باستخدام التعليمة <a href="https://wiki.hsoub.com/JavaScript/const" rel="external"><code>const</code></a> مع بعض الاستثناءات:
</p>

<ul>
	<li>
		عليك تهيئة الثابت عندما تعرّفه.
	</li>
	<li>
		لا يمكن أن تسند لها قيمة أخرى بعد تهيئتها. إذ يمكنك مثلًا التصريح عن المتغير باستخدام <code>let</code>دون أن تهيئه:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_68" style=""><span class="kwd">let</span><span class="pln"> count</span><span class="pun">;</span></pre>

<p>
	لكن إن حاولت أن تفعل ذلك باستخدام <code>const</code> سترى رسالة خطأ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_70" style=""><span class="kwd">const</span><span class="pln"> count</span><span class="pun">;</span></pre>

<p>
	يمكنك بعد التصريح عن متغير باستخدام <code>let</code> أن تهيئه في خطوة منفصلة (تُدعى بعملية إعادة اﻹسناد re-assigning):
</p>

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

<p>
	لكن إن حاولت ذلك عند استخدام <code>const</code> سترى رسالة خطأ أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_74" style=""><span class="kwd">const</span><span class="pln"> count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
count </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_5834_76" style=""><span class="kwd">const</span><span class="pln"> bird </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> species</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Kestrel"</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">bird</span><span class="pun">.</span><span class="pln">species</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "Kestrel"</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5834_78" style=""><span class="pln">bird</span><span class="pun">.</span><span class="pln">species </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Striated Caracara"</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">bird</span><span class="pun">.</span><span class="pln">species</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "Striated Caracara"</span></pre>

<h2 id="-18">
	متى نستخدم الثوابت والمتغيرات؟
</h2>

<p>
	لماذا نستخدم <code>const</code> إن لم تكن تفعل الكثير موازنة بالتعليمة <code>let</code>؟ لأن الواقع يقول أنها ذات فائدة كبيرة. فلو اطلع أي قارئ على شيفرة عُرّف فيها ثابت باستخدام <code>const</code> سيعرف بالتأكيد أن هذه القيمة لن تتغير لاحقًا وسيرتبط اسم هذا الثابت بقيمة ثابتة دائمًا.
</p>

<p>
	نتبنى في سلسلة مقالاتنا القاعدة التالية بخصوص <code>let</code> و <code>const</code> وهي كالتالي:<strong> استخدم <code>const</code> عندما تستطيع و <code>let</code> عندما يجب عليك ذلك</strong>. أي إن كنت تستطيع إسناد قيمة للمتغير عند التصريح عنه ولن تحتاج لتغييرها فصرّح عنه كثابت وإلا صرّح عنه كمتغير.
</p>

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

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

<p>
	ترجمة -وبتصرف- لمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables" rel="external nofollow">Storing the information you need-Variables</a>
</p>

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

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%88%D8%A5%D8%B9%D8%A7%D8%AF%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%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-r2286/" rel="">الدوال وإعادة استخدام الشيفرة في جافا سكريبت</a>
	</li>
	<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/%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>
</ul>
]]></description><guid isPermaLink="false">2287</guid><pubDate>Fri, 29 Mar 2024 12:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; &#x648;&#x625;&#x639;&#x627;&#x62F;&#x629; &#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x634;&#x64A;&#x641;&#x631;&#x629; &#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%AF%D9%88%D8%A7%D9%84-%D9%88%D8%A5%D8%B9%D8%A7%D8%AF%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%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-r2286/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_03/2058965661_.png.ea8de5c6b9add6ecad842980cca6a1ab.png" /></p>
<p>
	تُعد الدوال Functions من المفاهيم اﻷساسية في كتابة الشيفرة. إذ تسمح لك الدوال بتخزين عدة أسطر أو تعليمات تنفذ مهمة معينة ضمن كتلة معرّفة مسبقًا، وعندما تحتاج هذه الشيفرة في أي مكان تستدعي هذه الكتلة عبر تعليمة واحدة مختصرة، بدلًا من كتابة هذه الشيفرة عدة مرات. نتعرف إذًا في هذا المقال على المفاهيم الأساسية التي تعتمد عليها الدوال مثل الصياغة وطريقة التعريف والاستدعاء ومجال الرؤية والمعاملات.
</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>

<h2 id="-1">
	أين تجد الدوال؟
</h2>

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

<p>
	في كل مرة تستخدم بنية في جافا سكربت يليها قوسين <code>()</code> (باستثناء البنى الأصلية في اللغة مثل حلقة <code>for</code> أو حلقة <code>while</code> أو <code>for...else</code>) فأنت تستخدم دالة.
</p>

<h2 id="-2">
	الدوال اﻷصلية المدمجة في المتصفح
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_7" style=""><span class="kwd">const</span><span class="pln"> myText </span><span class="pun">=</span><span class="pln"> </span><span class="str">"I am a string"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> newString </span><span class="pun">=</span><span class="pln"> myText</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">"string"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"sausage"</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">newString</span><span class="pun">);</span><span class="pln">
</span><span class="com">// سلسلة نصية مصدرية replace() تأخذ الدالة</span><span class="pln">
</span><span class="com">// وأخرى هدف وتستبدل السلسلة المصدرية  </span><span class="pln">
</span><span class="com">//بالسلسلة الهدف وتعيد السلسلة النصية الجديدة</span></pre>

<p>
	أو في كل مرة تعاملنا فيها مع مصفوفات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_9" style=""><span class="kwd">const</span><span class="pln"> myArray </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"I"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"love"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"chocolate"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"frogs"</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> madeAString </span><span class="pun">=</span><span class="pln"> myArray</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="str">" "</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">madeAString</span><span class="pun">);</span><span class="pln">
</span><span class="com">// مصفوفة وتضم جميع عناصرها join() تأخذ الدالة</span><span class="pln">
</span><span class="com">// في سلسلة نصية جديدة وتعيد هذه السلسلة</span></pre>

<p>
	أو عندما ولدنا أعدادًا عشوائية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_11" style=""><span class="kwd">const</span><span class="pln"> myNumber </span><span class="pun">=</span><span class="pln"> </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="com">// عددًا عشوائيًا بين random() تولد الدالة</span><span class="pln">
</span><span class="com">//الرقم 0 و الرقم 1 (ما عدا 1)</span></pre>

<p>
	<strong>ملاحظة</strong>: جرّب الشيفرة السابقة في متصفحك (في طرفية جافا سكريبت) كي تتعود على استخدامها إن اقتضى اﻷمر.
</p>

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

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

<h2 id="-3">
	الدوال والتوابع
</h2>

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

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

<p>
	كما رأيت أيضًا في مقالاتنا السابق العديد من الدوال المخصصة، وهي دوال عرفناها ضمن الشيفرة وليست مدمجة مع المتصفح. فعندما ترى اسمًا مخصصًا يليه قوسين ستكون أمام دالة مخصصة. وكمثال عليها تجد الدالة <code>()draw</code> المخصصة التي استخدمناها ضمن الملف <a href="https://mdn.github.io/learning-area/javascript/building-blocks/loops/random-canvas-circles.html" rel="external nofollow">random-canvas-circles.html</a> (انظر <a href="https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/loops/random-canvas-circles.html" rel="external nofollow">الشيفرة المصدرية</a>) في مقال استخدام الحلقات في جافا سكريبت والذي يبدو كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_14" style=""><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"> WIDTH</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">WIDTH</span><span class="pun">),</span><span class="pln"> random</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">
    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></pre>

<p>
	ترسم الدالة 100 دائرة عشوائية ضمن العنصر <code><a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%B9%D9%86%D8%B5%D8%B1-canvas-%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%D8%A8%D8%AA-r207/" rel="">&lt;canvas&gt;</a></code>، وفي كل مرة نريد تكرار اﻷمر، نستدعي هذه الدالة كالتالي:
</p>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_18" style=""><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></pre>

<p>
	لقد احتجنا الدالة السابقة لأن الدالة اﻷصلية المدمجة <code>()Math.random</code> مع المتصفح تولد أرقامًا عشوائية عشرية بين 0 و 1 فقط، لكننا نريد رقمًا عشوائيًا صحيحًا بين 0 وقيمة معينة.
</p>

<h2 id="-4">
	استدعاء الدالة
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_23" style=""><span class="kwd">function</span><span class="pln"> myFunction</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">"hello"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

myFunction</span><span class="pun">();</span><span class="pln">
</span><span class="com">// يستدعي الدالة مرة واحدة</span></pre>

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

<h2 id="-5">
	معاملات الدالة
</h2>

<p>
	تحتاج بعض الدوال إلى معاملات parameters عند استدعائها، وهي قيم ينبغي وضعها ضمن قوسي الدالة كي تعمل الدالة بالشكل المطلوب.
</p>

<p>
	<strong>ملاحظة</strong>: تُدعى المعاملات أحيانًا "وسائطًا arguments" أو "خاصيات properties" أو "سمات attributes".
</p>

<p>
	وكمثال على ذلك، نجد دالة المتصفح <code>()Math.random</code> التي لا تأخذ أية معاملات وتعيد دومًا عددًا عشوائيًا بين 0 و1:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_25" style=""><span class="kwd">const</span><span class="pln"> myNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">();</span></pre>

<p>
	بينما تأخذ الدالة <code>()replace</code> معاملين هما النص الذي تريد إيجاده ضمن السلسلة الرئيسية والنص البديل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_27" style=""><span class="kwd">const</span><span class="pln"> myText </span><span class="pun">=</span><span class="pln"> </span><span class="str">"I am a string"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> newString </span><span class="pun">=</span><span class="pln"> myText</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">"string"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"sausage"</span><span class="pun">);</span></pre>

<p>
	<strong>ملاحظة</strong>: يُفصل بين المعاملات ما بين القوسين بفواصل من الشكل <code>,</code>.
</p>

<h3 id="-6">
	المعاملات الاختيارية
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_29" style=""><span class="kwd">const</span><span class="pln"> myArray </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"I"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"love"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"chocolate"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"frogs"</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> madeAString </span><span class="pun">=</span><span class="pln"> myArray</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="str">" "</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">madeAString</span><span class="pun">);</span><span class="pln">
</span><span class="com">//'I love chocolate frogs' تعيد الدالة</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> madeAnotherString </span><span class="pun">=</span><span class="pln"> myArray</span><span class="pun">.</span><span class="pln">join</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">madeAnotherString</span><span class="pun">);</span><span class="pln">
</span><span class="com">//'I,love,chocolate,frogs'تعيد الدالة </span></pre>

<p>
	فإن لم تخصص في الدالة المعامل الذي يمثل محرف الفصل أو الوصل، تستخدم الدالة الفاصلة افتراضيًا.
</p>

<h3 id="-7">
	المعاملات الافتراضية
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_31" style=""><span class="kwd">function</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="str">"Chris"</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="typ">Hello</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><span class="pln">

hello</span><span class="pun">(</span><span class="str">"Ari"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hello Ari!</span><span class="pln">
hello</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Hello Chris!</span></pre>

<h2 id="-8">
	الدوال غير المسماة والدوال السهمية
</h2>

<p>
	ما تعلمناه حتى اﻵن هو دالة من الشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_33" style=""><span class="kwd">function</span><span class="pln"> myFunction</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">"hello"</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_2560_35" style=""><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </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">"hello"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	تُدعى هذه الدوال بالدوال غير المسماة anonymous functions. وترى هذه الدوال عادة عندما تأخذ دالة ما دالة أخرى كمعامل لها، عندها يمرر المعامل كدالة غير مسماة.
</p>

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

<h3 id="-9">
	مثال عن الدوال غير المسماة Anonymous Functions
</h3>

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

<ul>
	<li>
		اسم الحدث الذي تترصده وهو في حالتنا الضغط على المفتاح <code>keydown</code>.
	</li>
	<li>
		دالة كي تُنفَّذ عندما يقع الحدث.
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_37" style=""><span class="kwd">function</span><span class="pln"> logKey</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">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="typ">You</span><span class="pln"> pressed </span><span class="str">"${event.key}"</span><span class="pun">.`);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

textBox</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"keydown"</span><span class="pun">,</span><span class="pln"> logKey</span><span class="pun">);</span></pre>

<p>
	وبدلًا من استخدام دالة منفصلة مثل <code>()logkey</code>، بإمكانك تمرير دالة غير مسماة إلى <code>()addEventListener</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_39" style=""><span class="pln">textBox</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"keydown"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </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">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="typ">You</span><span class="pln"> pressed </span><span class="str">"${event.key}"</span><span class="pun">.`);</span><span class="pln">
</span><span class="pun">});</span></pre>

<h3 id="-10">
	الدالة السهمية Arrow functions
</h3>

<p>
	إن مررت دالة إلى دالة أخرى على شكل دالة غير مسماة، ستجد طريقة أخرى لذلك تُدعى الدالة السهمية <code>&lt;=()</code> بدلًا من <code>()function</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_41" style=""><span class="pln">textBox</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"keydown"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</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="typ">You</span><span class="pln"> pressed </span><span class="str">"${event.key}"</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_2560_43" style=""><span class="pln">textBox</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"keydown"</span><span class="pun">,</span><span class="pln"> event </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="typ">You</span><span class="pln"> pressed </span><span class="str">"${event.key}"</span><span class="pun">.`);</span><span class="pln">
</span><span class="pun">});</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_45" style=""><span class="kwd">const</span><span class="pln"> originals </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</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="kwd">const</span><span class="pln"> doubled </span><span class="pun">=</span><span class="pln"> originals</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">item </span><span class="pun">=&gt;</span><span class="pln"> item </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</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">doubled</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [2, 4, 6]</span></pre>

<p>
	يأخذ التابع <code>()map</code> كل عنصر من عناصر المصفوفة بدوره ويمرر إلى دالة محددة ثم يعيد نتيجة تنفيذ هذه الدالة ويضيفها إلى المصفوفة الجديدة. فالعبارة البرمجية <code>item =&gt; item * 2</code> إذًا هو شكل مختصر للدالة السهمية ويكافئ تمامًا الدالة التصريحية التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_47" style=""><span class="kwd">function</span><span class="pln"> doubleItem</span><span class="pun">(</span><span class="pln">item</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"> item </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بإمكانك استخدام اﻷسلوب السابق لإعادة كتابة الدالة <code>addEventListener</code>:
</p>

<pre class="ipsCode">textBox.addEventListener("keydown", (event) =&gt;
  console.log(`You pressed "${event.key}".`),
);
</pre>

<p>
	تُعاد قيمة التابع <code>()console.log</code> (والتي هي قيمة غير محددة <code>undefined</code>) ضمنًا كنتيجة لاستدعاء الدالة.
</p>

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

<h3 id="-11">
	مثال مباشر عن استخدام الدالة السهمية
</h3>

<p>
	إلك مثالنا السابق عن التقاط ضغطة مفتاح:
</p>

<ul>
	<li>
		شيفرة HTML:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2560_49" style=""><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"textBox"</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;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"output"</span><span class="tag">&gt;&lt;/div&gt;</span></pre>

<ul>
	<li>
		شيفرة جافا سكريبت:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_51" style=""><span class="kwd">const</span><span class="pln"> textBox </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">"#textBox"</span><span class="pun">);</span><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><span class="pln">

textBox</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"keydown"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</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">
  output</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">You</span><span class="pln"> pressed </span><span class="str">"${event.key}"</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="200" loading="lazy" scrolling="no" src="https://codepen.io/HsoubAcademy/embed/YzMNmBy?default-tab=result" style="width: 100%;" title="functions">See the Pen functions by Hsoub Academy (@HsoubAcademy) on CodePen.</iframe>
</p>

<h2 id="-12">
	نطاق الدوال والتعارضات عند تفسير الشيفرة
</h2>

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

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

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

<ul>
	<li>
		ملف HTML:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2560_53" style=""><span class="com">&lt;!-- Excerpt from my HTML --&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">"first.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">"second.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  greeting</span><span class="pun">();</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<ul>
	<li>
		ملف جافا سكريبت الأول:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_55" style=""><span class="com">// first.js</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Chris"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> greeting</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</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><span class="pln"> welcome to our company</span><span class="pun">.`);</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
	<li>
		ملف جافا سكريبت الثاني:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_57" style=""><span class="com">// second.js</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Zaptec"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> greeting</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`</span><span class="typ">Our</span><span class="pln"> company is called $</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>()greeting</code>، لكنك لن تصل إلى إلى الدالة في الملف اﻷول (ستهمل الدالة في الثاني). إضافة إلى ذلك سيتوّلد خطأ إن حاولت (في الملف الثاني) إسناد قيمة جديدة إلى المتغير <code>name</code> لأنه عّرف مسبقًا على أنه ثابت <code>const</code> ولا يمكن إعادة إسناد قيمة له.
</p>

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

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="147066" href="https://academy.hsoub.com/uploads/monthly_2024_03/01_animal_cages_lime_functions_scope.png.04f54ac8ca8e890cc6ff0cbbef322fa5.png" rel=""><img alt="01 animal cages lime functions scope" class="ipsImage ipsImage_thumbnailed" data-fileid="147066" data-ratio="63.40" data-unique="i3bhgyx44" style="width: 500px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2024_03/01_animal_cages_lime_functions_scope.png.04f54ac8ca8e890cc6ff0cbbef322fa5.png"> </a>
</p>

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

<h3 id="-13">
	تطبيق عملي: التعامل مع نطاقات الرؤية
</h3>

<p>
	لنلق نظرة على مثال واقعي يوضح مفهوم المجالات.
</p>

<ol>
	<li>
		احفظ نسخة من <a href="https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/functions/function-scope.html" rel="external nofollow">ملف التمرين</a> على حاسوبك. ويتضمن الملف دالتين هما <code>()a</code> و <code>()b</code> وثلاثة متغيرات <code>x</code> و <code>y</code> و <code>z</code> اثنان منهما معرّفان ضمن الدالتين واﻷخير متغير عام. كما يتضمن الملف دالة ثالثة تُدعى تأخذ معاملًا واحدًا وتطبعه ضمن فقرة نصية في الصفحة.
	</li>
	<li>
		افتح التمرين ضمن المتصفح وضمن المحرر النصي.
	</li>
	<li>
		افتح طرفية جافا سكريبت ضمن أدوات مطوري ويب الخاصة بالمتصفح، ثم اكتب في الطرفية اﻷمر التالي:
	</li>
</ol>

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

<p>
	ينبغي أن ترى قيمة المتغير <code>x</code> قد طُبعت على الشاشة.
</p>

<ol start="4">
	<li>
		حاول اﻵن إدخال التالي في الطرفية:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_62" style=""><span class="pln">output</span><span class="pun">(</span><span class="pln">y</span><span class="pun">);</span><span class="pln">
output</span><span class="pun">(</span><span class="pln">z</span><span class="pun">);</span></pre>

<p>
	ينبغي أن ترمي كلا اﻷمرين خطأً (y غير معرّف y is not defined ). إن السبب في ذلك هو مجال الدالة. فكل من y و Z معرفان ضمن الدالة <code>()a</code> و <code>()b</code> فلا يمكن للدالة <code>()output</code> الوصول إليهما من النطاق العام.
</p>

<ol start="5">
	<li>
		لكن ما الذي سيحدث عندما نستدعيهما من داخل الدالة؟ حاول أن تغيّر الدالتين <code>()a</code> و <code>()b</code> كالتالي:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_64" style=""><span class="kwd">function</span><span class="pln"> a</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"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
  output</span><span class="pun">(</span><span class="pln">y</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"> b</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"> z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
  output</span><span class="pun">(</span><span class="pln">z</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	احفظ الشيفرة وأعد تحميل الصفحة ضمن المتصفح وحاول بعدها استدعاء الدالتين <code>()a</code> و <code>()b</code> من الطرفية:
</p>

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

<p>
	من المفترض أن ترى قيمتي y و z قد طبعتا على شاشة المتصفح، وسيعمل اﻷمر طالما أن الدالة <code>()output</code> قد استدعيت من داخل الدالتين <code>()a</code> و <code>()b</code> أي في نفس النطاق الذي عُرفت فيه المتغيرات وتبقى <code>()output</code> متاحة فيأي مكان طالما أنها ضمن النطاق العام
</p>

<ol start="6">
	<li>
		جرّب أن تغيّر الشيفرة لتصبح كالتالي:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_68" style=""><span class="kwd">function</span><span class="pln"> a</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"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
  output</span><span class="pun">(</span><span class="pln">x</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"> b</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"> z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
  output</span><span class="pun">(</span><span class="pln">x</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<ol start="5">
	<li>
		احفظ التغييرات وحاول أن تعيد تحميل الصفحة وجرّب ما يلي مجددًا في الطرفية:
	</li>
</ol>

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

<p>
	ستطبع الدالين الدالتين <code>()a</code> و <code>()b</code> قيمة x في المتصفح. سيعمل اﻷمر جيدًا لأنه وعلى الرغم من أن استدعائي الدالة لا ينتميان إلى نفس مجال x لكن x معرّف كمتغير عام، فهو متاح في أي مكان من الشيفرة
</p>

<ol start="6">
	<li>
		جرّب أخيرًا تحديث الشيفرة لتصبح كالتالي:
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2560_72" style=""><span class="kwd">function</span><span class="pln"> a</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"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
  output</span><span class="pun">(</span><span class="pln">z</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"> b</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"> z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
  output</span><span class="pun">(</span><span class="pln">y</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<ol start="7">
	<li>
		احفظ التغييرات وحاول أن تعيد تحميل الصفحة وجرّب ما يلي مجددًا في الطرفية:
	</li>
</ol>

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

<p>
	سيلقي اﻵن استدعاء الدالتين <code>()a</code> و <code>()b</code> نفس الخطأ (ReferenceError: variable name is not defined) في الطرفية لأن استدعاءات الدالة <code>()output</code> والمتغيرات التي تريد طباعة قيمتها لا ينتميان إلى نفس مجال أو نطاق الرؤية للدالة فهما غير مرئيان للاستدعاءات.
</p>

<p>
	<strong>ملاحظة</strong>: لا تُطبق نفس قواعد النطاق على الحلقات (مثل <code>{}()for</code>) والجمل الشرطية (مثل <code>{}()if</code>) فقد تبدوان مشابهتين للدوال لكنهما أمران مختلفان. انتبه إلى ذلك.
</p>

<p>
	<strong>ملاحظة</strong>: الخطأ ReferenceError: "x" is not defined من أكثر اﻷخطاء شيوعًا. ففي حال واجهت هذا الخطأ وأنت متأكد من أنك عرّفت المتغير، عليك في هذه الحالة مراجعة مجالات الرؤية.
</p>

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

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

<p>
	ترجمة -وبتصرف- للمقال <span ipsnoautolink="true"><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Functions#conclusion" rel="external nofollow">Functions- reusable bloacks of code</a></span><span style="display: none;"> </span>
</p>

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

<ul>
	<li>
		المقال السابق: <a href="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/" 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%D8%A8%D8%AA-r781/" rel="">الدوال في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r620/" rel="">الدوال Functions في جافا سكريبت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-function-object-%D9%88%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D9%85%D8%A7%D8%A9-nfe-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r875/" rel="">كائنات الدوال Function object وتعابير الدوال المسماة NFE في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B9%D9%84%D9%8A%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1242/" rel="">الدوال العليا في جافاسكريبت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2286</guid><pubDate>Tue, 26 Mar 2024 12:00:00 +0000</pubDate></item></channel></rss>
