<?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/11/?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>&#x627;&#x644;&#x643;&#x627;&#x626;&#x646; &#x627;&#x644;&#x639;&#x645;&#x648;&#x645;&#x64A; Global object &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86-%D8%A7%D9%84%D8%B9%D9%85%D9%88%D9%85%D9%8A-global-object-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r874/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_04/48.jpg.97b86cd84f7a0575dec86359040f710b.jpg" /></p>

<p>
	تقدّم الكائنات العمومية متغيراتَ ودوال يمكن استعمالها من أي مكان. هذه الكائنات مضمّنة في بنية اللغة أو البيئة مبدئيًا.
</p>

<p>
	في المتصفّحات تُدعى بالنافذة <code>‎window‎</code> وفي Node.js تُدعى بالعموميات <code>‎global‎</code> وفي باقي البيئات تُدعى بأيّ اسم مناسب يراه مطوّروها.
</p>

<p>
	أُضيف حديثًا الكائن <code>‎globalThis‎</code> إلى اللغة ليكون اسم قياسيًا للكائن العمومي على أن تدعمه كلّ البيئات. ولكن بعض المتصفّحات (وبالخصوص عدا Chromium Edge) لا تدعم هذا الكائن بعد، ولكن يمكنك «ترقيعه تعدّديًا» بسهولة تامة.
</p>

<p>
	سنستعمل هنا <code>‎window‎</code> على فرضية بأنّ البيئة هي المتصفّح نفسه. لو كنت ستشغّل السكربت الذي تكتبه في بيئات أخرى فربما تستعمل <code>‎globalThis‎</code> بدل النافذة تلك.
</p>

<p>
	يمكننا طبعًا الوصول إلى كافة خصائص الكائن العمومي مباشرةً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7875_7" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="str">"Hello"</span><span class="pun">);</span><span class="pln">
</span><span class="com">// تتطابق تمامًا مع</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">alert</span><span class="pun">(</span><span class="str">"Hello"</span><span class="pun">);</span></pre>

<p>
	يمكنك في المتصفّحات التصريح عن الدوال العمومية والمتغيرات باستعمال <code>‎var‎</code> (وليس <code>‎let/const‎</code> !) لتصير خاصيات للكائن العمومي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7875_9" style="">
<span class="kwd">var</span><span class="pln"> gVar </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">window</span><span class="pun">.</span><span class="pln">gVar</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫5 (تصير خاصية من خاصيات الكائن العمومي)</span></pre>

<p>
	ولكن أرجوك ألا تعتمد على هذا الأمر! هذا السلوك موجود للتوافقية لا غير. تستعمل السكربتات الحديثة «وحداتَ جافاسكربت» (نشرحها في وقت لاحق) حيث لا يحدث هكذا أمر.
</p>

<p>
	لن يحدث هذا لو استعملنا <code>‎let‎</code> هنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7875_11" style="">
<span class="pln">let gLet </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">window</span><span class="pun">.</span><span class="pln">gLet</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫غير معرّف (لا تصير خاصية للكائن العمومي)</span></pre>

<p>
	لو كانت القيمة هامّة جدًا جدًا وأردت أن تدخل عليها من أيّ مكان عمومي فاكتبها على أنّها خاصية مباشرةً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7875_13" style="">
<span class="com">// نجعل من معلومات المستخدم الحالي عمومية لتصل إليها كلّ السكربتات</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">currentUser </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">"John"</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// وفي مكان آخر يريدها أحد</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">currentUser</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln">  </span><span class="com">// John</span><span class="pln">

</span><span class="com">// ‫أو (لو كان هناك المتغير المحلي ذا الاسم «currentUser»</span><span class="pln">
</span><span class="com">// فنأخذها جهارةً من النافذة (وهذا آمن!)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">window</span><span class="pun">.</span><span class="pln">currentUser</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// John</span></pre>

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

<h2>
	استعمالها للترقيع تعدديًا
</h2>

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

<p>
	فمثلًا يمكننا اختبار لو كانت كائنات الوعود <code>‎Promise‎</code> المضمّنة في اللغة مضمّنة حقًا (لم تكن كذلك في المتصفحات العتيقة):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7875_15" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">window</span><span class="pun">.</span><span class="typ">Promise</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">"Your browser is really old!"</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_7875_18" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">window</span><span class="pun">.</span><span class="typ">Promise</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  window</span><span class="pun">.</span><span class="typ">Promise</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="com">// شيفرة نكتبها بنفسنا تؤدّي الميزة الحديثة في اللغة هذه</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	ملخص
</h2>

<ul>
<li>
		<p>
			يحمل الكائن العمومي تلك المتغيرات التي يلزم أن نصل إليها أينما كنّا في الشيفرة.
		</p>

		<p>
			تشمل المتغيرات هذه كل ما هو مضمّن في بنية لغة جافاسكربت مثل المصفوفات <code>‎Array‎</code> والقيم المخصّصة للبيئة مثل <code>‎window.innerHeight‎</code> (ارتفاع نافذة المتصفّح).
		</p>
	</li>
	<li>
		<p>
			للكائن العمومي اسم عام في المواصفة: <code>‎globalThis‎</code>.
		</p>

		<p>
			ولكن… دومًا ما نُشير إليه بالأسماء «الأثرية» حسب كل بيئة مثل <code>‎window‎</code> (في المتصفحات) و<code>‎global‎</code> (في Node.js)، إذ أنّ <code>‎globalThis‎</code> هو مُقترح جديد على اللغة وليس مدعومًا في المتصفّحات عدة Chromium Edge (ولكن يمكننا ترقيعه تعدّديًا).
		</p>
	</li>
	<li>
		<p>
			علينا ألا نخزّن القيم في الكائن العمومي إلّا لو كانت حقًا وفعلًا عمومية للمشروع الذي نعمل عليه. كما ويجب أن يبقى عددها بأقل ما يمكن.
		</p>
	</li>
	<li>
		<p>
			حين نطوّر لاستعمال الشيفرات في المتصفّحات (لو لم نستعمل الوحدات)، تصير الدوال العمومية والمتغيرات باستعمال <code>‎var‎</code> خاصيات للكائن العمومي. علينا استعمال خاصيات الكائن العمومي مباشرةً (مثل <code>‎window.x‎</code>) لتكون الشيفرة سهلة الصيانة مستقبلًا وأسهل فهمًا.
		</p>
	</li>
</ul>
<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/global-object" rel="external nofollow">Global object</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">874</guid><pubDate>Thu, 16 Apr 2020 12:42:38 +0000</pubDate></item><item><title>&#x625;&#x641;&#x627;&#x62F;&#x629; var &#x627;&#x644;&#x642;&#x62F;&#x64A;&#x645;&#x629; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A5%D9%81%D8%A7%D8%AF%D8%A9-var-%D8%A7%D9%84%D9%82%D8%AF%D9%8A%D9%85%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r873/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_04/47.jpg.f83e1a168172c0f928df37b6093fd500.jpg" /></p>

<p>
	ذكرنا في أوائل الفصول حين تكلمنا عن المتغيرات - ذكرنا ثلاث طرائق للتصريح عنها:
</p>

<ol>
<li>
		<code>let</code>
	</li>
	<li>
		<code>const</code>
	</li>
	<li>
		<code>var</code>
	</li>
</ol>
<p>
	تتصرّف كلا الإفادتين <code>‎let‎</code> و<code>‎const‎</code> بذات الطريقة (بالمقايسة مع البيئات المُعجمية).
</p>

<p>
	بينما <code>‎var‎</code> فهو وحش آخر مختلف جذريًا ويعود في أصله إلى قرون سحيقة. لا نستعمله عادةً في السكربتات الحديثة ولكنّك ستجده حتمًا خلف إحدى صخور السكربتات القديمة.
</p>

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

<p>
	من أول وهلة نرى بأنّ تصرّف <code>‎var‎</code> يشابه تصرّف <code>‎let‎</code>، أي أنّه يُصرّح (مثل الثاني) عن متغير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3220_7" style="">
<span class="kwd">function</span><span class="pln"> sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ‫متغير محلي، استعملنا «var» بدل «let»</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> phrase </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln"> 

  alert</span><span class="pun">(</span><span class="pln">phrase</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hello</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

sayHi</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">phrase</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫خطأ، phrase غير معرّف</span></pre>

<p>
	ولكن… ما خفي كان أعظم. إليك الفروق.
</p>

<h2>
	ليس لإفادة var نطاقًا كتليًا
</h2>

<p>
	حين نصرّح عن المتغيرات باستعمال <code>‎var‎</code> نكون جعلناها معروفة للدالة كاملةً (لو كانت في دالة) أو عمومية في السكربت. يمكنك أن ترى تلك المتغيرات إن اخترقت «جدران» الكُتل.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3220_9" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> test </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫نستعمل «var» بدل «let»</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">test</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫الناتج true، أي أنّ المتغير «حيّ يُرزق» بعد إفادة if</span></pre>

<p>
	تجاهل <code>‎var‎</code> كتل الشيفرة، وبهذا صار متغير <code>‎test‎</code> عموميًا.
</p>

<p>
	لو استعملنا <code>‎let test‎</code> بدل <code>‎var test‎</code> فسيكون المتغير ظاهرًا لباقي الشيفرة داخل إفادة <code>‎if‎</code> فقط لا غير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3220_11" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let test </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫نستعمل «let»</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">test</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫خطأ: لم يُعرّف عن test</span></pre>

<p>
	يسري الأمر ذاته على الحلقات فلا يمكن أن يكون <code>‎var‎</code> محليًا حسب الكتلة أو حسب الحلقة:
</p>

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

alert</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫10، ظهر «i» بعد الحلقة فهو متغير عمومي</span></pre>

<p>
	لو كتبت كتلة شيفرة في دالة فسيصير <code>‎var‎</code> متغيرًا على مستوى الدالة كاملةً.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3220_16" style="">
<span class="kwd">function</span><span class="pln"> sayHi</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">true</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"> phrase </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">phrase</span><span class="pun">);</span><span class="pln"> </span><span class="com">// يمكننا فعل هذا</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

sayHi</span><span class="pun">();</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">phrase</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫خطأ: phrase غير معرّف (طالِع مِعراض المطوّر)</span></pre>

<p>
	كما نرى فإفادة <code>‎var‎</code> تخترق كُتل <code>‎if‎</code> و<code>‎for‎</code> وغيرها من كُتل شيفرة. يعزو ذلك إلى أنّه في الزمن الماضي الجميل لم تكن لكُتل جافاسكربت بيئات مُعجمية. و<code>‎var‎</code> إحدى آثار ذلك الزمن.
</p>

<h2>
	تعالج التصريحات باستعمال <code>‎var‎</code> عند بدء الدالة
</h2>

<p>
	تُعالج التصريحات باستعمال <code>‎var‎</code> متى ما بدأت الدالة (أو بدأ السكربت، للمتغيرات العمومية).
</p>

<p>
	أي أنّ متغيرات <code>‎var‎</code> تُعرّف من بداية الدالة مهما كان مكان تعريفها (هذا لو لم يكن التعريف في دالة متداخلة أخرى).
</p>

<p>
	يعني ذلك أنّ هذه الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3220_18" style="">
<span class="kwd">function</span><span class="pln"> sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  phrase </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">phrase</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">var</span><span class="pln"> phrase</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
sayHi</span><span class="pun">();</span></pre>

<p>
	متطابقة تقنيًا مع هذه (بتحريك <code>‎var phrase‎</code> إلى أعلى):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3220_20" style="">
<span class="kwd">function</span><span class="pln"> sayHi</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"> phrase</span><span class="pun">;</span><span class="pln">

  phrase </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">phrase</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
sayHi</span><span class="pun">();</span></pre>

<p>
	أو حتى هذه (لا تنسَ بأنّ كُتل الشيفرات مُهملة):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3220_22" style="">
<span class="kwd">function</span><span class="pln"> sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  phrase </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">false</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"> phrase</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">phrase</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
sayHi</span><span class="pun">();</span></pre>

<p>
	يدعو الناس هذا السلوك بسلوك «الطفو» <em>hoisting</em> (أو الرفع) إذ أنّ متغيرات <code>‎var‎</code> «تطفو» إلى أعلى الدالة (أو ترتفع إلى أعلاها).
</p>

<p>
	أي أنّه في المثال أعلاه، الفرع <code>‎if (false)‎</code> من الإفادة لا يعمل قط ولكن هذا ليس بمهم، إذ أنّ <code>‎var‎</code> داخله سيُعالج في بداية الدالة، وحين تصل عملية التنفيذ إلى <code>‎(*)‎</code> سيكون المتغير موجودًا لا محالة.
</p>

<p>
	<strong>التصريحات تطفو صحيح، ولكنّ ليس عبارات الإسناد.</strong>
</p>

<p>
	الأفضل لو نمثّل ذلك في هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3220_24" style="">
<span class="kwd">function</span><span class="pln"> sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">phrase</span><span class="pun">);</span><span class="pln">  

  </span><span class="kwd">var</span><span class="pln"> phrase </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

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

<p>
	في السطر <code>‎var phrase = "Hello"‎</code> إجراءان اثنان:
</p>

<ol>
<li>
		التصريح عن المتغير باستعمال <code>var</code>
	</li>
	<li>
		إسناد قيمة للمتغير باستعمال <code>‎=‎</code>.
	</li>
</ol>
<p>
	يتعامل المحرّك مع التصريحات متى بدء تنفيذ الدالة (إذ التصريحات تطفو)، ولكنّ عبارة الإسناد لا تعمل إلّا حيثما ظهرت، فقط. إذًا فالشيفرة تعمل بهذا النحو فعليًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3220_26" style="">
<span class="kwd">function</span><span class="pln"> sayHi</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"> phrase</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫بادئ ذي بدء، يعمل التصريح...</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">phrase</span><span class="pun">);</span><span class="pln"> </span><span class="com">// غير معرّف</span><span class="pln">

  phrase </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫...هنا.</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

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

<p>
	يُعالج المحرّك التصريحات <code>‎var‎</code> حين تبدأ الدوال، وبهذا يمكننا الإشارة إليها أينما أردنا في الشيفرة. ولكن انتبه فالمتغيرات غير معرّفة حتى تُسند إليها قيم.
</p>

<p>
	في الأمثلة أعلاه عمل التابِع <code>‎alert‎</code> دون أيّ أخطاء إذ أن المتغير <code>‎phrase‎</code> موجود. ولكن لم تُسند فيه قيمة بعد فعرض <code>‎undefined‎</code>.
</p>

<h2>
	ملخص
</h2>

<p>
	هناك فرقين جوهرين بين <code>‎var‎</code> موازنةً بِـ <code>‎let/const‎</code>:
</p>

<ol>
<li>
		ليس لمتغيرات <code>‎var‎</code> نطاقًا كتليًا وأصغر نطاق لها هو في الدوال.
	</li>
	<li>
		تُعالج التصريحات باستعمال <code>‎var‎</code> عند بدء الدالة (أو بدء السكربت، للمتغيرات العمومية).
	</li>
</ol>
<p>
	هناك فرق آخر صغير يتعلّق بالكائن العمومي وسنشرحه في الفصل التالي.
</p>

<p>
	بهذا، غالبًا ما يكون استعمال <code>‎var‎</code> أسوأ بكثير من <code>‎let‎</code> بعدما عرفت الفروق بينها، فالمتغيرات على مستوى الكُتل أمر رائع جدًا ولهذا السبب تمامًا أُضيفت <code>‎let‎</code> إلى معيار اللغة منذ زمن وصارت الآن الطريقة الأساسية (هي و<code>‎const‎</code>) للتصريح عن متغير.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/var" rel="external nofollow">The old "var"</a><code>‎</code> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">873</guid><pubDate>Thu, 16 Apr 2020 12:36:09 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x646;&#x63A;&#x644;&#x642;&#x627;&#x62A; Closure &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_04/46.jpg.8628ec2757046eda77e66017ba5966ee.jpg" /></p>

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

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

<p>
	ولكن، ماذا يحدث حين يتغيّر المتغيّر الخارجي؟ هل تستلم الدالة أحدث قيمة له أو تلك التي كانت موجودة لحظة إنشاء الدالة؟
</p>

<p>
	كما وماذا يحدث حين تنتقل الدالة إلى مكان آخر في الشيفرة واستُدعت من ذلك المكان: هل يمكنها الوصول إلى المتغيرات الخارجية في المكان الجديد؟
</p>

<p>
	يختلف سلوك اللغات عن بعضها من هذه الناحية. في هذا الفصل سنتحدّث عن سلوك جافاسكربت.
</p>

<h2>
	أسئلة تحتاج أجوبة
</h2>

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

<ul>
<li>
		تستعمل الدالة <code>‎sayHi‎</code> المتغير الخارجي <code>‎name‎</code>. ما القيمة التي ستستعملها الدالة حين تعمل؟
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_7" style="">
<span class="pln">let name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> sayHi</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">"Hi, "</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">

name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Pete"</span><span class="pun">;</span><span class="pln">

sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ‫ماذا ستعرض؟ «John» أم «Pete»؟</span></pre>

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

<p>
	إذًا فالسؤال هو: هل تستعمل آخر التعديلات؟
</p>

<ul>
<li>
		تصنع الدالة <code>‎makeWorker‎</code> دالةً أخرى وتُعيدها، ويمكن أن نستعدي تلك الدالة الجديدة من أيّ مكان آخر نريد. السؤال هو: هل يمكنها الوصول إلى المتغيرات الخارجية تلك التي من مكان إنشائها الأصلي، أم تلك التي في المكان الجديد، أم من المكانين معًا؟
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_11" style="">
<span class="kwd">function</span><span class="pln"> makeWorker</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Pete"</span><span class="pun">;</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">
    alert</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">

let name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// نصنع الدالة</span><span class="pln">
let work </span><span class="pun">=</span><span class="pln"> makeWorker</span><span class="pun">();</span><span class="pln">

</span><span class="com">// نستدعيها</span><span class="pln">
work</span><span class="pun">();</span><span class="pln"> </span></pre>

<p>
	‫ماذا ستعرض الدالة <code>work()‎</code>؟ «Pete» (الاسم الذي تراه عند الإنشاء) أم «John» (الاسم الذي تراه عند الاستدعاء)؟
</p>

<h2>
	البيئات المعجمية
</h2>

<p>
	علينا أولًا أن نعرف ما هو «المتغير» هذا أصلًا لنُدرك ما يجري بالضبط.
</p>

<p>
	في لغة جافاسكربت، تملك كلّ دالة عاملة أو كتلة شفرات <code>‎{...}‎</code> أو حتّى السكربت كلّه - تملك كائنًا داخليًا مرتبطًا بها (ولكنّه مخفي) يُدعى <em>بالبيئة المُعجمية</em> <em>Lexical Environment</em>.
</p>

<p>
	تتألّف كائنات البيئات المُعجمية هذه من قسمين:
</p>

<ol>
<li>
		<em>سجلّ مُعجمي</em> <em>Environment Record</em>: وهو كائن يخزّن كافة المتغيرات المحلية على أنّها خاصيات له (كما وغيرها من معلومات مثل قيمة <code>‎this‎</code>).
	</li>
	<li>
		إشارة إلى <em>البيئة المُعجمية الخارجية</em> - أي المرتبطة مع الشيفرة الخارجية للكائن المُعجمي.
	</li>
</ol>
<p>
	<strong>ليس «المتغير» إلا خاصية لإحدى الكائنات الداخلية الخاصة: السجل المُعجمي <code>‎Environment Record‎</code>. وحين نعني «بأخذ المتغير أو تغيير قيمته» فنعني «بأخذ خاصية ذلك الكائن أو تغيير قيمتها».</strong>
</p>

<p>
	إليك هذه الشيفرة البسيطة مثالًا (فيها بيئة مُعجمية واحدة فقط):
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37861" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-environment-global.png.9d726c4a406b38ee0a8965355ccfdfbe.png" rel=""><img alt="lexical-environment-global.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37861" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-environment-global.png.9d726c4a406b38ee0a8965355ccfdfbe.png"></a>
</p>

<p>
	هذا ما نسمّيه البيئة المُعجمية العمومية (global) وهي مرتبطة بالسكربت كاملًَا.
</p>

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

<p>
	وهكذا تتغيّر البيئة حين تعرّف عن متغيّر وتُسند له قيمة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37859" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-environment-global-2.png.50b8246aeef5a683f2dbe839c5f1dd1c.png" rel=""><img alt="lexical-environment-global-2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37859" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-environment-global-2.png.50b8246aeef5a683f2dbe839c5f1dd1c.png"></a>
</p>

<p>
	نرى في المستطيلات على اليمين كيف تتغيّر البيئة المُعجمية العمومية أثناء تنفيذ الشيفرة:
</p>

<ol>
<li>
		حين تبدأ الشيفرة، تكون البيئة المُعجمية فارغة.
	</li>
	<li>
		بعدها يظهر التصريح <code>‎let phrase‎</code>، لكن لم تُسند للمتغيّر أيّ قيمة، لذا تخزّن البيئة <code>‎undefined‎</code>.
	</li>
	<li>
		تُسند للمتغير <code>‎phrase‎</code> قيمة.
	</li>
	<li>
		وهنا تتغيّر قيمة <code>‎phrase‎</code>.
	</li>
</ol>
<p>
	بسيط حتّى الآن، أم لا؟
</p>

<p>
	نلخّص الموضوع:
</p>

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

<p>
	لم نرى حتّى اللحظة إلا المتغيرات. حان وقت التصريحات بالدوال.
</p>

<p>
	<strong>الدوال على عكس متغيرات <code>‎let‎</code>، فليست تُهيّأ تمامًا حين تصلها عملية التنفيذ، لا، بل قبل ذلك حين تُنشأ البيئة المُعجمية.</strong>
</p>

<p>
	وحين نتكلم عن أعلى الدوال مستوًى، فنعني ذلك لحظة بدء السكربت.
</p>

<p>
	ولهذا السبب يمكننا استدعاء الدوال التي صرّحناها حتّى قبل أن نرى ذاك التعريف.
</p>

<p>
	نرى في الشيفرة أدناه كيف أنّ البيئة المُعجمية تحتوي شيئًا منذ بداية التنفيذ (وليست فارغة)، وما تحتويه هي <code>‎say‎</code> إذ أنّها تصريح عن دالة. وبعدها تسجّل <code>‎phrase‎</code> المُصرّح باستعمال <code>‎let‎</code>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37860" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-environment-global-3.png.dce44dec125fe2f2c61f4f1ca54962e3.png" rel=""><img alt="lexical-environment-global-3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37860" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-environment-global-3.png.dce44dec125fe2f2c61f4f1ca54962e3.png"></a>
</p>

<h3>
	البيئات المُعجمية الداخلية والخارجية
</h3>

<p>
	الآن لنتعمّق ونرى ما يحدث حين تحاول الدالة الوصول إلى متغير خارجي.
</p>

<p>
	تستعمل <code>‎say()‎</code> أثناء الاستعداء المتغير الخارجي <code>‎phrase‎</code>. لنرى تفاصيل ما يجري بالضبط.
</p>

<p>
	تُنشأ بيئة مُعجمية تلقائيًا ما إن تعمل الدالة وتخزّن المتغيرات المحلية ومُعاملات ذلك الاستدعاء
</p>

<p>
	فمثلًا هكذا تبدو بيئة استدعاء <code>‎say("John")‎</code> (وصل التنفيذ السطر الذي عليه سهم):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_13" style="">
<span class="pln">let phrase </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">function</span><span class="pln"> say</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">
 alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`‎</span><span class="pln">$</span><span class="pun">{</span><span class="pln">phrase</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">
</span><span class="pun">}</span><span class="pln">

say</span><span class="pun">(</span><span class="str">"John"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hello, John</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37863" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-environment-simple.png.8e097f8d1bebddca2a4a3b4b4b9b6ecb.png" rel=""><img alt="lexical-environment-simple.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37863" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-environment-simple.png.8e097f8d1bebddca2a4a3b4b4b9b6ecb.png"></a>
</p>

<p>
	إذًا… حين نكون داخل استدعاءً لأحد الدوال نرى لدينا بيئتين مُعجميتين: الداخلية (الخاصة باستدعاء الدالة) والخارجية (العمومية):
</p>

<ul>
<li>
		<p>
			ترتبط البيئة المُعجمية الداخلية مع عملية التنفيذ الحالية للدالة <code>‎say‎</code>.
		</p>

		<p>
			تملك خاصية واحدة فقط: <code>‎name‎</code> (وسيط الدالة). ونحن استدعينا <code>‎say("John")‎</code> بهذا تكون قيمة <code>‎name‎</code> هي <code>‎"John"‎</code>.
		</p>
	</li>
	<li>
		<p>
			البيئة المُعجمية الخارجية وهي هنا البيئة المُعجمية العمومية.
		</p>

		<p>
			تملك متغير <code>‎phrase‎</code> والدالة ذاتها.
		</p>
	</li>
</ul>
<p>
	للبيئة المُعجمية الداخلية إشارة إلى تلك «الخارجية».
</p>

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

<p>
	لو لم يوجد المتغير في عملية البحث تلك فسترى خطأً (لو استعملت النمط الصارم <em>Strict Mode</em>). لو لم تستعمل <code>‎use strict‎</code> فسيُنشئ الإسناد إلى متغير غير موجود (مثل <code>‎user = "John"‎</code>) متغيرًا عموميًا جديدًا باسم <code>‎user‎</code>. سبب ذلك هو التوافق مع الإصدارات السابقة.
</p>

<p>
	لنرى عملية البحث تلك في مثالنا:
</p>

<ul>
<li>
		حين تحاول <code>‎alert‎</code> في دالة <code>‎say‎</code> الوصول إلى المتغير <code>‎name‎</code> تجده مباشرةً في البيئة المُعجمية للدالة.
	</li>
	<li>
		وحين تحاول الوصول إلى متغير <code>‎phrase‎</code> ولا تجده محليًا، تتبع الإشارة في البيئة المحلية وتصل البيئة المُعجمية خارجها، وتجد المتغير فيها.
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37862" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-environment-simple-lookup.png.524a9ab8a226c4527ec7383ccbf7f512.png" rel=""><img alt="lexical-environment-simple-lookup.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37862" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-environment-simple-lookup.png.524a9ab8a226c4527ec7383ccbf7f512.png"></a>
</p>

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

<p>
	<strong>تأخذ الدالة المتغيرات الخارجية من مكانها الآن، أي أنها تستعمل أحدث القيم.</strong>
</p>

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

<p>
	إذًا، إجابة السؤال الأول هي <code>‎Pete‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_15" style="">
<span class="pln">let name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> sayHi</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">"Hi, "</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">

name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Pete"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">

sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// (*) Pete</span></pre>

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

<ol>
<li>
		للبيئة المُعجمية العمومية <code>‎name: "John"‎</code>.
	</li>
	<li>
		في السطر <code>‎(*)‎</code> يتغيّر المتغير العمومي ويصير الآن <code>‎name: "Pete"‎</code>.
	</li>
	<li>
		تأخذ الدالة <code>‎sayHi()‎</code> حين تتنفّذ قيمة <code>‎name‎</code> من الخارج (أي البيئة المُعجمية العمومية) حيث صارت الآن <code>‎"Pete"‎</code>.
	</li>
</ol>
<p>
	<strong>لكلّ استدعاء منك، بيئة مُعجمية من اللغة</strong> لاحظ بأنّ محرّك اللغة يُنشئ بيئة مُعجمية جديدة للدالة في كلّ مرة تعمل فيها الدالة.
</p>

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

<p>
	<strong>البيئات المُعجمية كائن في توصيف اللغة</strong> كائن «البيئة المُعجمية» (Lexical Environment) هو كائن في توصيف اللغة، أي أنّه موجود «نظريًا» فقط في <a href="https://tc39.es/ecma262/#sec-lexical-environments" rel="external nofollow">توصيف اللغة</a> لشرح طريقة عمل الأمور، ولا يمكننا أخذ هذا الكائن في الشيفرة ولا التعديل عليه مباشرةً. كما يمكن أن تُحسّن محرّكات جافاسكربت هذا الكائن أو تُهمل المتغيرات غير المستخدمة فتحفظ الذاكرة أو غيرها من خُدع داخلية، كلّ هذا بمنأًى عن السلوك الظاهر لنا فيظلّ كما هو.
</p>

<h2>
	الدوال المتداخلة
</h2>

<p>
	تكون الدالة «متداخلة» متى صنعتها داخل دالة أخرى.
</p>

<p>
	ويمكنك بسهولة بالغة فعل ذلك داخل جافاسكربت.
</p>

<p>
	يمكننا استعمال هذه الميزة لتنظيم الشيفرة الإسباغيتية، هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_17" style="">
<span class="kwd">function</span><span class="pln"> sayHiBye</span><span class="pun">(</span><span class="pln">firstName</span><span class="pun">,</span><span class="pln"> lastName</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// دالة مساعدة متداخلة نستعملها أسفله</span><span class="pln">
  </span><span class="kwd">function</span><span class="pln"> getFullName</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"> firstName </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> lastName</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Hello, "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> getFullName</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Bye, "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> getFullName</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

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

<p>
	صنعنا هنا الدالة <em>المتداخلة</em> <code>‎getFullName()‎</code> لتسهّل حياتنا علينا، فيمكنها هي الوصول إلى المتغيرات الخارجية وإعادة اسم الشخص الكامل. كثيرًا ما نستعمل الدوال المتداخلة في جافاسكربت.
</p>

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

<p>
	مثال على ذلك: أسندنا الدالة المتداخلة إلى كائن جديد باستعمال <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D8%A7%D9%86%D9%8A-%D9%88%D8%A7%D9%84%D8%B9%D8%A7%D9%85%D9%84-new-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r801/" rel="">دالة مُنشئة</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_19" style="">
<span class="com">// تُعيد الدالة المُنشئة كائنًا جديدًا</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// نصنع تابِع الكائن على أنّه دالة متداخلة</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sayHi </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">
    alert</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">

let user </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="str">"John"</span><span class="pun">);</span><span class="pln">
</span><span class="com">// ‫يمكن أن تصل شيفرة تابِع الكائن «sayHi» إلى «name» الخارجي</span><span class="pln">
user</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span></pre>

<p>
	وهنا أنشأنا دالة «عدّ» وأعدناها، لا أكثر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_21" style="">
<span class="kwd">function</span><span class="pln"> makeCounter</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let count </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="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ‫يمكنها الوصول إلى  متغير «count» الخارجي</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> count</span><span class="pun">++;</span><span class="pln"> 
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let counter </span><span class="pun">=</span><span class="pln"> makeCounter</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> counter</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> counter</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> counter</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span></pre>

<p>
	لنتفحّص مثال <code>‎makeCounter‎</code>. تصنع الشيفرة دالة «العدّ» وتُعيد العدد التالي كلّما استدعيناها. صحيح أنّ الدالة بسيطة لكن بتعديلها قليلًا يمكن استعمالها لأمور عديدة مفيدة مثل <a href="https://ar.wikipedia.org/wiki/%D9%85%D9%88%D9%84%D8%AF_%D8%A3%D8%B9%D8%AF%D8%A7%D8%AF_%D8%B4%D8%A8%D9%87_%D8%B9%D8%B4%D9%88%D8%A7%D8%A6%D9%8A%D8%A9" rel="external nofollow">مولّدات الأعداد شبه العشوائية</a> وغيرها.
</p>

<p>
	ولكن كيف يعمل هذا العدّاد داخليًا؟
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37864" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-search-order.png.3695007d26a5071481723a6f9b9b2349.png" rel=""><img alt="lexical-search-order.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37864" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexical-search-order.png.3695007d26a5071481723a6f9b9b2349.png"></a>
</p>

<ol>
<li>
		المتغيرات المحلية للدالة المتداخلة…
	</li>
	<li>
		المتغيرات المحلية للدالة الخارجية…
	</li>
	<li>
		وهكذا حتى نصل المتغيرات العمومية.
	</li>
</ol>
<p>
	في هذا المثال وجدنا المتغير <code>‎count‎</code> في الخطوة الثانية. فلو عُدّلت قيمة المتغير الخارجي فيحدث هذا التعديل في المكان الذي وجدنا المتغير فيه. لهذا تجد <code>‎count++‎</code> المتغير الخارجي وتزيد قيمته في البيئة المُعجمية التي ينتمي المتغير إليها، تمامًا كما لو استعملنا <code>‎let count = 1‎</code>.
</p>

<p>
	إليك سؤالين تفكّر بهما (أيضًا):
</p>

<ol>
<li>
		هل يمكننا بطريقة أو بأخرى تصفير العدّاد <code>‎count‎</code> من الشيفرة التي لا تنتمي إلى <code>‎makeCounter‎</code>؟ مثلًا بعد استدعاءات <code>‎alert‎</code> في المثال أعلاه.
	</li>
	<li>
		حين نستعدي <code>‎makeCounter()‎</code> أكثر من مرة تُعيد لنا دوال <code>‎counter‎</code> كثيرة. فهل هي مستقلة بذاتها أم تتشارك ذات متغير <code>‎count‎</code>؟
	</li>
</ol>
<p>
	حاول حلّ السؤالين قبل مواصلة القراءة.
</p>

<p>
	انتهيت؟
</p>

<p>
	إذًا حان وقت الإجابات.
</p>

<ol>
<li>
		ما من طريقة أبدًا: متغير <code>‎count‎</code> هو متغير محلي داخل إحدى الدوال ولا يمكننا الوصول إليه من الخارج.
	</li>
	<li>
		كلّ استدعاء من <code>‎makeCounter()‎</code> يصنع بيئة مُعجمية جديدة للدالة لها متغير <code>‎count‎</code> خاص بها. لذا فدوال <code>‎counter‎</code> الناتج مستقلة عن بعضها البعض.
	</li>
</ol>
<p>
	إليك شيئًا تجربّه بنفسك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_23" style="">
<span class="kwd">function</span><span class="pln"> makeCounter</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let count </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="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> count</span><span class="pun">++;</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let counter1 </span><span class="pun">=</span><span class="pln"> makeCounter</span><span class="pun">();</span><span class="pln">
let counter2 </span><span class="pun">=</span><span class="pln"> makeCounter</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> counter1</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> counter1</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> counter2</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫0 (مستقل)</span></pre>

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

<h2>
	البيئات بالتفصيل الممل
</h2>

<p>
	إليك ما يجري في مثال <code>‎makeCounter‎</code> خطوةً بخطوة. احرص على اتباعه لتحرص على فهم آلية عمل البيئات بالتفصيل.
</p>

<p>
	لاحظ أنّا شرحنا الخاصية الإضافية <code>‎[[Environment]]‎</code> هنا، ولم نشرحها سابقًا للتبسيط.
</p>

<ol>
<li>
		<p>
			حين يبدأ السكربت لا يكون هناك إلى بيئة مُعجمية عمومية:
		</p>

		<p style="text-align: center;">
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37852" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-1.png.24d6a92f6bc1cc65267f66da607fd369.png" rel=""><img alt="lexenv-nested-makecounter-1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37852" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-1.png.24d6a92f6bc1cc65267f66da607fd369.png"></a>
		</p>

		<p>
			في تلك اللحظة ليس هناك إلا دالة <code>‎makeCounter‎</code> إذ أنها تصريح عن دالة، ولم يبدأ تشغيلها بعد.
		</p>

		<p>
			<strong>تستلم كافة الدوال «لحظة إفاقتها للحياة» خاصية مخفية باسم <code>‎[[Environment]]‎</code> فيها إشارة إلى البيئة المُعجمية حيث أُنشئت.</strong>
		</p>

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

		<p>
			هنا أُنشأت <code>‎makeCounter‎</code> في البيئة المُعجمية العمومية، ولهذا فتُبقي <code>‎[[Environment]]‎</code> إشارة إليها.
		</p>

		<p>
			أي وبعبارة أخرى، «نطبع» على الدالة إشارةً للبيئة المُعجمية التي نشأت فيها، وخاصية <code>‎[[Environment]]‎</code> هي الخاصية الدالية المخفية التي تسجّل تلك الإشارة.
		</p>
	</li>
	<li>
		<p>
			تبدأ أخيرًا الشيفرة بالعمل، ويرى المحرّك متغيرا عموميًا جديدًا بالاسم <code>‎counter‎</code> صرّحنا عنه وقيمته هي ناتج استعداء <code>‎makeCounter()‎</code>. إليك نظرة على اللحظة التي تكون فيها عملية التنفيذ على أول سطر داخل <code>‎makeCounter()‎</code>:
		</p>

		<p style="text-align: center;">
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37853" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-2.png.4f0b14e44c825d29271efc860766840e.png" rel=""><img alt="lexenv-nested-makecounter-2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37853" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-2.png.4f0b14e44c825d29271efc860766840e.png"></a>
		</p>

		<p>
			تُنشأ بيئة مُعجمية لحظة استدعاء <code>‎makeCounter()‎</code> لتحمل متغيراتها ومُعاملاتها.
		</p>

		<p>
			وكما الحال مع البيئات هذه فهي تخزّن أمرين:
		</p>

		<ol>
<li>
				سجلّ بيئي فيه المتغيرات المحلية. في حالتنا هنا متغير <code>‎count‎</code> هو الوحيد المحلي (يظهر حين يُنفّذ سطر <code>‎let count‎</code>).
			</li>
			<li>
				الإشارة إلى البيئة المُعجمية الخارجية (وتُضبط قيمة لخاصية <code>‎[[Environment]]‎</code> للدالة). تُشير هنا <code>‎[[Environment]]‎</code> للدالة <code>‎makeCounter‎</code> إلى البيئة المُعجمية العمومية.
			</li>
		</ol>
<p>
			إذًا لدينا بيئتين مُعجميتين اثنتين: الأولى عمومية والثانية مخصّصة لاستدعاء <code>‎makeCounter‎</code> الحالي، بينما الإشارة الخارجية لها هي البيئة العمومية.
		</p>
	</li>
	<li>
		<p>
			تُصنع -أثناء تنفيذ <code>‎makeCounter()‎</code>- دالة صغيرة متداخلة.
		</p>

		<p>
			لا يهمّنا إن كان التصريح عن الدالة أم تعبير الدالة هو من أنشأ… الدالة، فالخاصية <code>‎[[Environment]]‎</code> تُضاف لكل الدوال، وتُشير إلى البيئة المُعجمية التي صُنعت فيها تلك الدوال. وبطبيعة الحال فهذه الدالة الصغيرة المتداخلة لديها نصيب من الكعكة.
		</p>

		<p>
			قيمة الخاصية <code>‎[[Environment]]‎</code> للدالة المتداخلة هذه هي البيئة المُعجمية الحالية للدالة <code>‎makeCounter()‎</code> (مكان صناعة الدالة المتداخلة):
		</p>

		<p style="text-align: center;">
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37854" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-3.png.d193ace89eaac6150f2a787226a69ea3.png" rel=""><img alt="lexenv-nested-makecounter-3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37854" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-3.png.d193ace89eaac6150f2a787226a69ea3.png"></a>
		</p>

		<p>
			لاحظ أنّ الدالة الداخلية (في هذه الخطوة) أُنشئت صحيح ولكن لم نستعدها بعد. الشيفرة في <code>‎return count++;‎</code> لا تعمل.
		</p>
	</li>
	<li>
		<p>
			تُواصل عملية التنفيذ العمل وينتهي استدعاء <code>‎makeCounter()‎</code> ويُسند ناتجها (وهو الدالة المتداخلة الصغيرة) إلى المتغير العمومي <code>‎counter‎</code>:
		</p>

		<p style="text-align: center;">
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37855" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-4.png.28816fe8a82abe919042c92cdafa622d.png" rel=""><img alt="lexenv-nested-makecounter-4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37855" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-4.png.28816fe8a82abe919042c92cdafa622d.png"></a>
		</p>

		<p>
			ليس لتلك الدالة إلا سطرًا واحدًا: <code>‎return count++‎</code> وسيُنفّذ ما إن نشغّل الدالة.
		</p>
	</li>
	<li>
		<p>
			وحين استدعاء <code>‎counter()‎</code> تُنشأ بيئة مُعجمية جديدة، لكنّها فارغة إذ أن ليس للدالة <code>‎counter‎</code> متغيرات محلية فيها، إلّا أنّ لخاصية الدالة <code>‎counter‎</code>‏ <code>‎[[Environment]]‎</code> فائدة ففيها الإشارة «الخارجية» للدالة وهي التي تتيح لنا الوصول إلى متغيرات استدعاء <code>‎makeCounter()‎</code> السابق متى ما أنشأناه:
		</p>

		<p style="text-align: center;">
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37856" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-5.png.e57246c1da216d0d0121414e95efea68.png" rel=""><img alt="lexenv-nested-makecounter-5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37856" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-5.png.e57246c1da216d0d0121414e95efea68.png"></a>
		</p>

		<p>
			أما الآن فحين يبحث الاستدعاء عن متغير <code>‎count‎</code> فهو يبحث أولًا في بيئته المُعجمية (الفارغة)، فلو لم يجدها بحث في البيئة المُعجمية لاستدعاء <code>‎makeCounter()‎</code> الخارجي، ويجد المتغير فيه.
		</p>

		<p>
			لاحظ آلية إدارة الذاكرة هنا. صحيح أنّ استدعاء <code>‎makeCounter()‎</code> انتهى قبل فترة إلا أن بيئته المُعجمية بقيت في الذاكرة لأنّ الدالة المتداخلة تحمل الخاصية <code>‎[[Environment]]‎</code> التي تُشير إلى تلك البيئة.
		</p>

		<p>
			يمكن القول بصفة عامة بأنّ البيئة المُعجمية لا تموت طالما يمكن لدالة من الدوال استعمالها. وحين لا توجد هكذا دالة - حينها تُمسح البيئة.
		</p>
	</li>
	<li>
		<p>
			لا يُعيد استدعاء <code>‎counter()‎</code> قيمة الخاصية <code>‎count‎</code> فحسب، بل أيضًا يزيدها واحدًا. لاحظ كيف أنّ التعديل حدث «في ذات مكانه» <em>In place</em>، فتعدّلت قيمة <code>‎count‎</code> في البيئة ذاتها التي وجدناه فيها.
		</p>

		<p style="text-align: center;">
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37857" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-6.png.62520f075f42d8c43b20ba63a7a7372c.png" rel=""><img alt="lexenv-nested-makecounter-6.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37857" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-makecounter-6.png.62520f075f42d8c43b20ba63a7a7372c.png"></a>
		</p>
	</li>
	<li>
		<p>
			تعمل استدعاءات <code>‎counter()‎</code> التالية بنفس الطريقة.
		</p>
	</li>
</ol>
<p>
	أفترض الآن بأنّ إجابة السؤال الثاني في أول الفصل ستكون جليّة.
</p>

<p>
	دالة <code>‎work()‎</code> في الشيفرة أدناه تأخذ الاسم <code>‎name‎</code> من مكانه الأصل عبر إشارة البيئة المُعجمية الخارجية إليه:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37858" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-work.png.e3c125503407d99499d65a944f71662c.png" rel=""><img alt="lexenv-nested-work.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37858" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-nested-work.png.e3c125503407d99499d65a944f71662c.png"></a>
</p>

<p>
	إذًا، فالناتج هنا هو <code>‎"Pete"‎</code>.
</p>

<p>
	ولكن لو لم نكتب <code>‎let name‎</code> في <code>‎makeWorker()‎</code> فسينتقل البحث إلى خارج الدالة تلك ويأخذ القيمة العمومية كما نرى من السلسلة أعلاه. في تلك الحالة سيكون الناتج <code>‎"John"‎</code>.
</p>

<p>
	<strong>المنغلقات</strong> هناك مصطلح عام يُستعمل في البرمجة باسم «المُنغلِق» <em>Clousure</em> ويُفترض أن يعلم به المطوّرون.
</p>

<p>
	<a href="https://en.wikipedia.org/wiki/Closure_(computer_programming)" rel="external nofollow">المُنغِلق</a> هو دالة تتذكّر متغيراتها الخارجية كما ويمكنها أن تصل إليها. هذا الأمر -في بعض اللغات- مستحيل، أو أنّه يلزم كتابة الدالة بطريقة معيّنة ليحدث ذلك. ولكن كما شرحنا أعلاه ففي لغة جافاسكربت، كلّ الدوال مُنغلِقات بطبيعتها (وطبعًا ثمّة استثناء واحد أوحد نشرحه في فصل «صياغة الدالة الجديدة»).
</p>

<p>
	يعني ذلك بأنّ الدوال تتذكّر أين أُنشئت باستعمال خاصية <code>‎[[Environment]]‎</code> المخفية، كما ويمكن للدوال كافة الوصول إلى متغيراتها الخارجية.
</p>

<p>
	لو كنت عزيزي مطوّر الواجهات في مقابلةً وأتاك السؤال «ما هو المُنغلِق؟» فيمكنك أن تقدّم تعريفه شرحًا، كما وتُضيف بأنّ الدوال في جافاسكربت كلّها مُنغلِقات، وربما شيء من عندك تفاصيل تقنية مثل خاصية <code>‎[[Environment]]‎</code> وطريقة عمل البيئات المُعجمية.
</p>

<h2>
	كُتل الشفرات والحلقات، تعابير الدوال الآنية
</h2>

<p>
	ركّزتُ في الأمثلة أعلاه على الدوال، إلا أنّ البيئة المُعجمية موجودة لكلّ كتلة شيفرات <code>‎{...}‎</code>.
</p>

<p>
	تُنشأ البيئة المُعجمية حين تعمل أيّ كتلة شيفرات فيها متغيرات تُعدّ محلية لهذه الكتلة. إليك بعض الأمثلة.
</p>

<h3>
	الجملة الشرطية If
</h3>

<p>
	في المثال أسفله نرى المتغير <code>‎user‎</code> موجودًا فقط داخل كتلة <code>‎if‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_27" style="">
<span class="pln">let phrase </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">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let user </span><span class="pun">=</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">;</span><span class="pln">

    alert</span><span class="pun">(`‎</span><span class="pln">$</span><span class="pun">{</span><span class="pln">phrase</span><span class="pun">},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">user</span><span class="pun">}‎`);</span><span class="pln"> </span><span class="com">// Hello, John</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫خطأ! لا أرى هذا المتغير!</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37850" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-if.png.c523e63322cc36056d1838569d9248f0.png" rel=""><img alt="lexenv-if.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37850" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-if.png.c523e63322cc36056d1838569d9248f0.png"></a>
</p>

<p>
	حين تصل عملية التنفيذ داخل كتلة <code>‎if‎</code> يُنشئ المحرك البيئة المُعجمية «فقط وفقط إذا كذا…».
</p>

<p>
	لهذه البيئة إشارة إلى البيئة الخارجية، بهذا يمكن أن تجد المتغير <code>‎phrase‎</code>. ولكن على العكس فالمتغيرات وتعابير الدوال المصرَّح عنها داخل <code>‎if‎</code> في تلك البيئة المُعجمية لا يمكن أن نراها من الخارج.
</p>

<p>
	فمثلًا بعدما تنتهي إفادة <code>‎if‎</code> لن يرى التابِع <code>‎alert‎</code> أسفلها متغير <code>‎user‎</code>، وهذا سبب الخطأ.
</p>

<h3>
	حلقة «كرّر طالما»
</h3>

<p>
	لكلّ دورة في حلقة التكرار بيئة مُعجمية خاصة بها. وأيضًا لو صرّحت عن متغير في <code>‎for(let ...)‎</code> فسيكون موجودًا فيها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_29" style="">
<span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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="com">// {i: value}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln"> </span><span class="com">// خطأ، ما من متغير كهذا</span></pre>

<p>
	لاحظ كيف أنّ الإفادة <code>‎let i‎</code> خارج كتلة <code>‎{...}‎</code> بصريًا. مُنشئ حلقة <code>‎for‎</code> خاص نوعًا ما: لكلّ دورة من الحقة بيئة مُعجمية خاصة بها تحمل قيمة <code>‎i‎</code> الحالية فيها أيضًا.
</p>

<p>
	وكما مع <code>‎if‎</code> فبعد انتهاء الحلقة لا نرى <code>‎i‎</code> خارجها.
</p>

<h3>
	كتل الشفرات
</h3>

<p>
	يمكننا أيضًا استعمال كتلة شفرات<code>‎{…}‎</code> «مجرّدة» لنعزل المتغيرات في «نطاق محلي» خاص بها.
</p>

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

<p>
	يمكن أن يحدث هذا لو كان اسم المتغير كلمة شائعة (مثلًا <code>‎name‎</code>) ولا يدري مطورو السكربتات ما يفعله الغير.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_31" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// نُجري أمرًا على المتغيرات المحلية يُمنع على ما خارجنا رؤيته</span><span class="pln">

  let message </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">message</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hello</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">message</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫خطأ: message غير معرّف</span></pre>

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

<h3>
	تعابير الدوال الآنية IIFE
</h3>

<p>
	سابقًا لم تكن هناك بيئات مُعجمية للكُتل في جافاسكربت.
</p>

<p>
	وكما «الحاجة أمّ الاختراع»، فكان على المطوّرين حلّ ذلك، وهكذا صنعوا ما سمّوه «تعابير الدوال آنيّة الاستدعاء» <em><strong>I</strong>mmediately-<strong>I</strong>nvoked <strong>F</strong>unction <strong>E</strong>xpressions</em>.
</p>

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

<p>
	إليك شكل الدوال الآنية هذه:
</p>

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

  let message </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">message</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hello</span><span class="pln">

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

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_35" style="">
<span class="com">// نحاول التصريح عن الدالة واستدعائها آنيًا</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">// &lt;-- Error: Unexpected token (</span><span class="pln">

  let message </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">message</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hello</span><span class="pln">

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

<p>
	حتّى لو قلنا «طيب لنضيف ذلك الاسم» فلن ينفع إذ أنّ محرّك جافاسكربت لا يسمح باستدعاء التصاريح عن الدوال آنيًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_37" style="">
<span class="com">// خطأ صياغي بسبب الأقواس أسفله</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> go</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

</span><span class="pun">}();</span><span class="pln"> </span><span class="com">// &lt;-- لا يمكن أن نستدعي التصريح عن الدوال آنيًا</span></pre>

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

<p>
	ثمّة طرق أخرى دون الأقواس لنُقنع المحرّك بأنّ ما نعني هو تعبير الدالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_39" style="">
<span class="com">// طرائق إنشاء هذه التعابير الآنية</span><span class="pln">

</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="str">"أقواس تحيط بالدالة"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">})</span><span class="pln"> </span><span class="pun">();</span><span class="pln">

</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="str">"أقواس تحيط بكامل الجملة"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}()</span><span class="pln"> </span><span class="pun">);</span><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">
  alert</span><span class="pun">(</span><span class="str">"عملية الأعداد الثنائية NOT أوّل التعبير"</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="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="str">"عملية الجمع الأحادية أوّل التعبير"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}();</span></pre>

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

<h2>
	كنس المهملات
</h2>

<p>
	عادةً ما تُمسح وتُحذف البيئة المُعجمية بعدما تعمل الدالة. مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_41" style="">
<span class="kwd">function</span><span class="pln"> f</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let value1 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">123</span><span class="pun">;</span><span class="pln">
  let value2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">456</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

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

<p>
	هنا القيمتين (تقنيًا) خاصيتين للبيئة المُعجمية. ولكن حين تنتهي <code>‎f()‎</code> لا يمكن أن نصل إلى تلك البيئة بأيّ طريقة فتُحذف من الذاكرة.
</p>

<p>
	…ولكن لو كانت هناك دالة متداخلة يمكن أن نصل إليها بعدما تنتهي <code>‎f‎</code> (ولديها خاصية <code>‎[[Environment]]‎</code> التي تُشير إلى البيئة المُعجمية الخارجية)، لو كانت فيمكن أن نصل إليها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_43" style="">
<span class="kwd">function</span><span class="pln"> f</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let value </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">function</span><span class="pln"> g</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln">value</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"> g</span><span class="pun">;</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let func </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ‫يمكن أن تصل func الآن بإشارة إلى g</span><span class="pln">
</span><span class="com">// بذلك تبقى في الذاكرة، ومعها بيئتها المُعجمية الخارجية</span></pre>

<p>
	لاحظ بأنّه لو استدعينا <code>‎f()‎</code> أكثر من مرة، فسوف تُحفظ الدوال الناتجة منها وتبقى كائنات البيئة المُعجمية لكلّ واحدة منها في الذاكرة. إليك ثلاثة منها في الشيفرة أدناه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_45" style="">
<span class="kwd">function</span><span class="pln"> f</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let value </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="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"> alert</span><span class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// في المصفوفة ثلاث دوال تُشير كلّ منها إلى البيئة المُعجمية</span><span class="pln">
</span><span class="com">// ‫في عملية التنفيذ f()‎ المقابلة لكلّ واحدة</span><span class="pln">
let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">f</span><span class="pun">(),</span><span class="pln"> f</span><span class="pun">(),</span><span class="pln"> f</span><span class="pun">()];</span></pre>

<p>
	يموت كائن البيئة المُعجمية حين لا يمكن أن يصل إليه شيء (كما الحال مع أيّ كائن آخر). بعبارة أخرى فهو موجود طالما ثمّة دالة متداخلة واحدة (على الأقل) في الشيفرة تُشير إليه.
</p>

<p>
	في الشيفرة أسفله، بعدما تصير <code>‎g‎</code> محالة الوصول تُمسح بيئتها المُعجمية فيها (ومعها متغير <code>‎value‎</code>) من الذاكرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_49" style="">
<span class="kwd">function</span><span class="pln"> f</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let value </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">function</span><span class="pln"> g</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln">value</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"> g</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// ‫طالما يمكن أن تصل func بإشارة إلى g، ستظلّ تشغل حيّزًا في الذاكرة</span><span class="pln">
let func </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">();</span><span class="pln"> 

</span><span class="com">// ...والآن لم تعد كذلك ونكون قد نظّفنا الذاكرة</span><span class="pln">
func </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"> </span></pre>

<h3>
	التحسينات على أرض الواقع
</h3>

<p>
	كما رأينا، فنظريًا طالما الدالة «حيّة تُرزق» تبقى معها كل متغيراتها الخارجية.
</p>

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

<p>
	<strong>ثمّة -في محرّك V8 (كروم وأوبرا)- تأثير مهمّ ألا وهو أنّ هذا المتغير لن يكون مُتاحًا أثناء التنقيح.</strong>
</p>

<p>
	جرّب تشغيل المثال الآتي في «أدوات المطوّرين» داخل متصفّح كروم.
</p>

<p>
	ما إن يُلبث تنفيذ الشيفرة، اكتب <code>‎alert(value)‎</code> في الطرفية.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_51" style="">
<span class="kwd">function</span><span class="pln"> f</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let value </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="kwd">function</span><span class="pln"> g</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">debugger</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫اكتب في المِعراض: alert(value);‎ ما من متغير كهذا!</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> g</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let g </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">();</span><span class="pln">
g</span><span class="pun">();</span></pre>

<p>
	كما رأينا، ما من متغير كهذا! يُفترض نظريًا أن نصل إليه ولكنّ المحرّك حسّن أداء الشيفرة وحذفه.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_53" style="">
<span class="pln">let value </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Surprise!"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> f</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let value </span><span class="pun">=</span><span class="pln"> </span><span class="str">"the closest value"</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">function</span><span class="pln"> g</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">debugger</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫اكتب في المِعراض: alert(value);‎ إليك Surprise!</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> g</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let g </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">();</span><span class="pln">
g</span><span class="pun">();</span></pre>

<p>
	<strong>إلى فصل آخر!</strong> من المفيد معرفة هذه الميزة في معيار V8. متى ما بدأت التنقيح في كروم أو أوبرا، فستراها شئت أم أبيت.
</p>

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

<h2>
	تمارين
</h2>

<h3>
	هل العدّادات مستقلة عن بعضها البعض؟
</h3>

<p>
	<em>الأهمية: 5</em>
</p>

<p>
	صنعنا هنا عدّادين اثنين <code>‎counter‎</code> و <code>‎counter2‎</code> باستعمال ذات الدالة <code>‎makeCounter‎</code>.
</p>

<p>
	هل هما مستقلان عن بعضهما البعض؟ ما الذي سيعرضه العدّاد الثاني؟ <code>‎0,1‎</code> أم <code>‎2,3‎</code> أم ماذا؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_55" style="">
<span class="kwd">function</span><span class="pln"> makeCounter</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let count </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="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> count</span><span class="pun">++;</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let counter </span><span class="pun">=</span><span class="pln"> makeCounter</span><span class="pun">();</span><span class="pln">
let counter2 </span><span class="pun">=</span><span class="pln"> makeCounter</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> counter</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> counter</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> counter2</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ؟</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> counter2</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ؟</span></pre>

<h4>
	الحل
</h4>

<p>
	الإجابة هي: <strong>0,1</strong>.
</p>

<p>
	صنعنا الدالتين <code>‎counter‎</code> و <code>‎counter2‎</code> باستدعاءين <code>‎makeCounter‎</code> مختلفين تمامًا.
</p>

<p>
	لذا فلكلّ منهما بيئات مُعجمية خارجية مستقلة عن بعضها، ولكلّ منهما متغير <code>‎count‎</code> مستقل عن الثاني.
</p>

<h3>
	كائن عد
</h3>

<p>
	<em>الأهمية: 5</em>
</p>

<p>
	هنا صنعنا كائن عدّ بمساعدة دالة مُنشئة <em>Constructor Function</em>.
</p>

<p>
	هل ستعمل؟ ماذا سيظهر؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_57" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Counter</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let count </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">this</span><span class="pun">.</span><span class="pln">up </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">++</span><span class="pln">count</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">down </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">--</span><span class="pln">count</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let counter </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Counter</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> counter</span><span class="pun">.</span><span class="pln">up</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ؟</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> counter</span><span class="pun">.</span><span class="pln">up</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ؟</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> counter</span><span class="pun">.</span><span class="pln">down</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ؟</span></pre>

<h4>
	الحل
</h4>

<p>
	طبعًا، ستعمل كما يجب.
</p>

<p>
	صُنعت الدالتين المتداخلتين في نفس البيئة المُعجمية الخارجية، بهذا تتشاركان نفس المتغير <code>‎count‎</code> وتصلان إليه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_59" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Counter</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let count </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">this</span><span class="pun">.</span><span class="pln">up </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">++</span><span class="pln">count</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">down </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">--</span><span class="pln">count</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let counter </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Counter</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> counter</span><span class="pun">.</span><span class="pln">up</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> counter</span><span class="pun">.</span><span class="pln">up</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> counter</span><span class="pun">.</span><span class="pln">down</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span></pre>

<h3>
	دالة في شرط if
</h3>

<p>
	طالِع الشيفرة أسفله. ما ناتج الاستدعاء في آخر سطر؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_61" style="">
<span class="pln">let phrase </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">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let user </span><span class="pun">=</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">function</span><span class="pln"> sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(`‎</span><span class="pln">$</span><span class="pun">{</span><span class="pln">phrase</span><span class="pun">},</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">user</span><span class="pun">}‎`);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

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

<h4>
	الحل
</h4>

<p>
	الناتج هو: <strong>خطأ</strong>.
</p>

<p>
	صُرّح عن الدالة <code>‎sayHi‎</code> داخل الشرط <code>‎if‎</code> وتعيش فيه فقط لا غير. ما من دالة <code>‎sayHi‎</code> خارجية.
</p>

<h3>
	المجموع باستعمال المُنغلِقات
</h3>

<p>
	<em>الأهمية: 4</em>
</p>

<p>
	اكتب الدالة <code>‎sum‎</code> لتعمل هكذا: <code>‎sum(a)(b) = a+b‎</code>.
</p>

<p>
	نعم عينك سليمة، هكذا تمامًا باستعمال قوسين اثنين (ليست خطأً مطبعيًا).
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_63" style="">
<span class="pln">sum</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)(</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
sum</span><span class="pun">(</span><span class="lit">5</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"> </span><span class="lit">4</span></pre>

<h4>
	الحل
</h4>

<p>
	ليعمل القوسين الثانيين، يجب أن يُعيد الأوليين دالة.
</p>

<p>
	هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_65" style="">
<span class="kwd">function</span><span class="pln"> sum</span><span class="pun">(</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">return</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</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">return</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫تأخذ «a» من البيئة المُعجمية الخارجية</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="pln"> sum</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)(</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> sum</span><span class="pun">(</span><span class="lit">5</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"> </span><span class="com">// 4</span></pre>

<h3>
	الترشيح عبر دالة
</h3>

<p>
	<em>الأهمية: 5</em>
</p>

<p>
	نعلم بوجود التابِع <code>‎arr.filter(f)‎</code> للمصفوفات. ووظيفته هي ترشيح كلّ العناصر عبر الدالة <code>‎f‎</code>. لو أرجعت <code>‎true‎</code> فيُعيد التابِع العنصر في المصفوفة الناتجة.
</p>

<p>
	اصنع مجموعة مرشّحات «جاهزة لنستعملها مباشرة»:
</p>

<ul>
<li>
		<code>‎inBetween(a, b)‎</code> -- بين <code>‎a‎</code> و<code>‎b‎</code>بما فيه الطرفين (أي باحتساب <code>‎a‎</code> و<code>‎b‎</code>).
	</li>
	<li>
		<code>‎inArray([...])‎</code> -- في المصفوفة الممرّرة.
	</li>
</ul>
<p>
	هكذا يكون استعمالها:
</p>

<ul>
<li>
		<code>‎arr.filter(inBetween(3,6))‎</code> -- تحدّد القيم بين 3 و6 فقط.
	</li>
	<li>
		<code>‎arr.filter(inArray([1,2,3]))‎</code> -- تحدّد العناصر المتطابقة مع أحد عناصر <code>‎[1,2,3]‎</code> فقط.
	</li>
</ul>
<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_67" style="">
<span class="com">// .. ‫شيفرة الدالتين inBetween وinArray</span><span class="pln">
let arr </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="lit">4</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">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">inBetween</span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">))</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3,4,5,6</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">inArray</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">10</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1,2</span></pre>

<h4>
	الحل
</h4>

<ol>
<li>
		المرشّح <code>inBetween</code>
	</li>
</ol>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_69" style="">
<span class="kwd">function</span><span class="pln"> inBetween</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</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">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"> x </span><span class="pun">&gt;=</span><span class="pln"> a </span><span class="pun">&amp;&amp;</span><span class="pln"> x </span><span class="pun">&lt;=</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let arr </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="lit">4</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">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">];</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">inBetween</span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">))</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3,4,5,6</span></pre>

<ol start="2">
<li>
		المرشّح <code>inArray</code>
	</li>
</ol>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_71" style="">
<span class="kwd">function</span><span class="pln"> inArray</span><span class="pun">(</span><span class="pln">arr</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">function</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"> arr</span><span class="pun">.</span><span class="pln">includes</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="pun">}</span><span class="pln">

let arr </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="lit">4</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">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">];</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">inArray</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">10</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1,2</span></pre>

<h3>
	الترشيح حسب حقل الاستمارة
</h3>

<p>
	<em>الأهمية: 5</em>
</p>

<p>
	أمامنا مصفوفة كائنات علينا ترتيبها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_73" style="">
<span class="pln">let users </span><span class="pun">=</span><span class="pln"> </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">"John"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20</span><span class="pun">,</span><span class="pln"> surname</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Johnson"</span><span class="pln"> </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">"Pete"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">18</span><span class="pun">,</span><span class="pln"> surname</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Peterson"</span><span class="pln"> </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">"Ann"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">19</span><span class="pun">,</span><span class="pln"> surname</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Hathaway"</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_2976_75" style="">
<span class="com">// ‫حسب الاسم (Ann, John, Pete)</span><span class="pln">
users</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">((</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">name </span><span class="pun">&gt;</span><span class="pln"> b</span><span class="pun">.</span><span class="pln">name </span><span class="pun">?</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">);</span><span class="pln">

</span><span class="com">// ‫حسب العمر (Pete, Ann, John)</span><span class="pln">
users</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">((</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">age </span><span class="pun">&gt;</span><span class="pln"> b</span><span class="pun">.</span><span class="pln">age </span><span class="pun">?</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">);</span></pre>

<p>
	هل يمكن أن تكون بحروف أقل، هكذا مثلًا؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_77" style="">
<span class="pln">users</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">byField</span><span class="pun">(</span><span class="str">'name'</span><span class="pun">));</span><span class="pln">
users</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">byField</span><span class="pun">(</span><span class="str">'age'</span><span class="pun">));</span></pre>

<p>
	أي، بدل أن نكتب دالة، نضع <code>‎byField(fieldName)‎</code> فقط.
</p>

<p>
	اكتب الدالة <code>‎byField‎</code> لنستعملها هكذا.
</p>

<h4>
	الحل
</h4>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_79" style="">
<span class="pln">let users </span><span class="pun">=</span><span class="pln"> </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">"John"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20</span><span class="pun">,</span><span class="pln"> surname</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Johnson"</span><span class="pln"> </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">"Pete"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">18</span><span class="pun">,</span><span class="pln"> surname</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Peterson"</span><span class="pln"> </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">"Ann"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">19</span><span class="pun">,</span><span class="pln"> surname</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Hathaway"</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"> byField</span><span class="pun">(</span><span class="pln">field</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">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">field</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> b</span><span class="pun">[</span><span class="pln">field</span><span class="pun">]</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

users</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">byField</span><span class="pun">(</span><span class="str">'name'</span><span class="pun">));</span><span class="pln">
users</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">user </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name</span><span class="pun">));</span><span class="pln"> </span><span class="com">// Ann, John, Pete</span><span class="pln">

users</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">byField</span><span class="pun">(</span><span class="str">'age'</span><span class="pun">));</span><span class="pln">
users</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">user </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name</span><span class="pun">));</span><span class="pln"> </span><span class="com">// Pete, Ann, John</span></pre>

<h3>
	جيش عرمرم من الدوال
</h3>

<p>
	<em>الأهمية: 5</em>
</p>

<p>
	تصنع الشيفرة الآتية مصفوفة من مُطلقي النار <code>‎shooters‎</code>.
</p>

<p>
	يفترض أن تكتب لنا كلّ دالة رقم هويّتها، ولكن ثمّة خطب فيها…
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_81" style="">
<span class="kwd">function</span><span class="pln"> makeArmy</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let shooters </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">

  let i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let shooter </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// دالة مُطلق النار</span><span class="pln">
      alert</span><span class="pun">(</span><span class="pln"> i </span><span class="pun">);</span><span class="pln"> </span><span class="com">// المفترض أن ترينا رقمها</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
    shooters</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">shooter</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">return</span><span class="pln"> shooters</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let army </span><span class="pun">=</span><span class="pln"> makeArmy</span><span class="pun">();</span><span class="pln">

army</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]();</span><span class="pln"> </span><span class="com">// مُطلق النار بالهويّة 0 يقول أنّه 10</span><span class="pln">
army</span><span class="pun">[</span><span class="lit">5</span><span class="pun">]();</span><span class="pln"> </span><span class="com">// ‫مُطلق النار بالهويّة 5 يقول أنّه 10...</span><span class="pln">
</span><span class="com">// ... كلّ مُطلقي النار يقولون 10 بدل هويّاتهم 0 فَـ 1 فَـ 2 فَـ 3...</span></pre>

<p>
	لماذا هويّة كلّ مُطلق نار نفس البقية؟ أصلِح الشيفرة لتعمل كما ينبغي أن تعمل.
</p>

<h4>
	الحل
</h4>

<p>
	لنُجري مسحًا شاملًا على ما يجري في <code>‎makeArmy‎</code>، حينها يظهر لنا الحل جليًا.
</p>

<ol>
<li>
		<p>
			تُنشئ مصفوفة <code>‎shooters‎</code> فارغة:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_83" style="">
<span class="pln">let shooters </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span></pre>

		<p>
			 
		</p>
	</li>
	<li>
		<p>
			تملأ المصفوفة في حلقة عبر <code>‎shooters.push(function...)‎</code>.
		</p>

		<p>
			كلّ عنصر هو دالة، بهذا تكون المصفوفة الناتجة هكذا:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_85" style="">
<span class="pln">shooters </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="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</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">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="pln">i</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="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</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">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="pln">i</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="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</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">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="pln">i</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="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</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">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="pln">i</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="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</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">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="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>
			 
		</p>
	</li>
	<li>
		<p>
			تُعيد الدالة المصفوفة.
		</p>
	</li>
</ol>
<p>
	لاحقًا، يستلم استدعاء <code>‎army[5]()‎</code> العنصر <code>‎army[5]‎</code> من المصفوفة، وهي دالة فيستدعيها.
</p>

<p>
	الآن، لماذا تعرض كلّ هذه الدوال نفس الناتج؟
</p>

<p>
	يعزو ذلك إلى عدم وجود أيّ متغير محلي باسم <code>‎i‎</code> في دوال <code>‎shooter‎</code>. فحين تُستدعى هذه الدالة تأخذ المتغير <code>‎i‎</code> من البيئة المُعجمية الخارجية.
</p>

<p>
	وماذا ستكون قيمة <code>‎i‎</code>؟
</p>

<p>
	لو رأينا مصدر القيمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_87" style="">
<span class="kwd">function</span><span class="pln"> makeArmy</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">...</span><span class="pln">
  let i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let shooter </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// دالة مُطلق النار</span><span class="pln">
      alert</span><span class="pun">(</span><span class="pln"> i </span><span class="pun">);</span><span class="pln"> </span><span class="com">// المفترض أن ترينا رقمها</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما نرى… «تعيش» القيمة في البيئة المُعجمية المرتبطة بدورة <code>‎makeArmy()‎</code> الحالية. ولكن متى استدعينا <code>‎army[5]()‎</code>، تكون دالة <code>‎makeArmy‎</code> قد أنهت مهمّتها فعلًا وقيمة <code>‎i‎</code> هي آخر قيمة، أي <code>‎10‎</code> (قيمة نهاية حلقة <code>‎while‎</code>).
</p>

<p>
	وبهذا تأخذ كلّ دوال <code>‎shooter‎</code> القيمة من البيئة المُعجمية الخارجية، ذات القيمة الأخيرة <code>‎i=10‎</code>.
</p>

<p>
	يمكن أن نُصلح ذلك بنقل تعريف المتغير إلى داخل الحلقة:
</p>

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

  let shooters </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">

  </span><span class="com">// (*)</span><span class="pln">
  </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let 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">
    let shooter </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// دالة مُطلق النار</span><span class="pln">
      alert</span><span class="pun">(</span><span class="pln"> i </span><span class="pun">);</span><span class="pln"> </span><span class="com">// المفترض أن ترينا رقمها</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
    shooters</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">shooter</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"> shooters</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let army </span><span class="pun">=</span><span class="pln"> makeArmy</span><span class="pun">();</span><span class="pln">

army</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]();</span><span class="pln"> </span><span class="com">// 0</span><span class="pln">
army</span><span class="pun">[</span><span class="lit">5</span><span class="pun">]();</span><span class="pln"> </span><span class="com">// 5</span></pre>

<p>
	الآن صارت تعمل كما يجب إذ في كلّ مرة تُنفّذ كتلة الشيفرة في <code>‎for (let i=0...) {...}‎</code>، يُنشئ المحرّك بيئة مُعجمية جديدة لها فيها متغير <code>‎i‎</code> المناسب لتلك الكتلة.
</p>

<p>
	إذًا لنلخّص: قيمة <code>‎i‎</code> صارت «تعيش» أقرب للدالة من السابق. لم تعد في بيئة <code>‎makeArmy()‎</code> المُعجمية بل الآن في تلك البيئة المخصّصة لدورة الحلقة الحالية. هكذا صارت تعمل كما يجب.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37851" href="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-makearmy.png.69d0b49a5ab7679ae61a50b29d39ed14.png" rel=""><img alt="lexenv-makearmy.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37851" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/lexenv-makearmy.thumb.png.9a866a745a3f95fa58ed4da402f5ccc8.png"></a>
</p>

<p>
	أعدنا كتابة الشيفرة هنا وعوّضنا <code>‎while‎</code> بحلقة <code>‎for‎</code>.
</p>

<p>
	يمكننا أيضًا تنفيذ حيلة أخرى. لنراها لنفهم الموضوع أكثر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2976_91" style="">
<span class="kwd">function</span><span class="pln"> makeArmy</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let shooters </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">

  let i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let j </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
    let shooter </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// دالة مُطلق النار</span><span class="pln">
      alert</span><span class="pun">(</span><span class="pln"> j </span><span class="pun">);</span><span class="pln"> </span><span class="com">// (*) المفترض أن ترينا رقمها</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
    shooters</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">shooter</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">return</span><span class="pln"> shooters</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let army </span><span class="pun">=</span><span class="pln"> makeArmy</span><span class="pun">();</span><span class="pln">

army</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]();</span><span class="pln"> </span><span class="com">// 0</span><span class="pln">
army</span><span class="pun">[</span><span class="lit">5</span><span class="pun">]();</span><span class="pln"> </span><span class="com">// 5</span></pre>

<p>
	كما حلقة <code>‎for‎</code>، فحلقة <code>‎while‎</code> تصنع بيئة مُعجمية جديدة لكلّ دورة، وهكذا نتأكّد بأن تكون قيمة <code>‎shooter‎</code> صحيحة.
</p>

<p>
	باختصار ننسخ القيمة <code>‎let j = i‎</code> وهذا يصنع المتغير <code>‎j‎</code> المحلي داخل الحلقة وينسخ قيمة <code>‎i‎</code> إلى نفسه. تُنسخ الأنواع الأولية «حسب قيمتها» <em>By value</em>، لذا بهذا نأخذ نسخة كاملة مستقلة تمامًا عن <code>‎i‎</code>، ولكنّها مرتبطة بالدورة الحالية في الحلقة.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/closure" rel="external nofollow">Closure</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">872</guid><pubDate>Mon, 13 Apr 2020 18:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x639;&#x627;&#x645;&#x644;&#x627;&#x62A; &#x627;&#x644;&#x628;&#x642;&#x64A;&#x629; &#x648;&#x645;&#x639;&#x627;&#x645;&#x644; &#x627;&#x644;&#x62A;&#x648;&#x632;&#x64A;&#x639; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D8%B9%D8%A7%D9%85%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D9%82%D9%8A%D8%A9-%D9%88%D9%85%D8%B9%D8%A7%D9%85%D9%84-%D8%A7%D9%84%D8%AA%D9%88%D8%B2%D9%8A%D8%B9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r871/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_04/45.jpg.f1ca27e6564aceb16e7124f3c8f791aa.jpg" /></p>

<p>
	تتوقّع العديد من دوال جافاسكربت المضمّنة في اللغة عددًا من الوُسطاء لا ينتهي.
</p>

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

<ul>
<li>
		<code>‎Math.max(arg1, arg2, ..., argN)‎</code> -- يُعيد أكبر وسيط من الوُسطاء.
	</li>
	<li>
		<code>‎Object.assign(dest, src1, ..., srcN)‎</code> -- ينسخ الخصائص من <code>‎src1..N‎</code> إلى <code>‎dest‎</code>.
	</li>
	<li>
		…وهكذا.
	</li>
</ul>
<p>
	سنتعلّم في هذا الفصل كيف نفعل ذلك أيضًا. كما وكيف نمرّر المصفوفات إلى هذه الدوال على أنّها مُعاملات.
</p>

<h2>
	المعاملات «البقية» <code>...</code>
</h2>

<p>
	يمكن أن ننادي الدالة بأيّ عدد من الوُسطاء كيفما كانت معرّفة الدالة.
</p>

<p>
	هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_7" style="">
<span class="kwd">function</span><span class="pln"> sum</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> sum</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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	لن ترى أيّ خطأ بسبب تلك الوُسطاء «الزائدة». ولكن طبعًا فالنتيجة لن تأخذ بالحسبان إلا أوّل اثنين.
</p>

<p>
	يمكن تضمين بقية المُعاملات في تعريف الدالة باستعمال الثلاث نقاط <code>‎...‎</code> ثمّ اسم المصفوفة التي ستحتويهم. تعني تلك النقط حرفيًا «اجمع المُعاملات الباقية في مصفوفة».
</p>

<p>
	فمثلًا لجمع كلّ الوُسطاء في المصفوفة <code>‎args‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_9" style="">
<span class="kwd">function</span><span class="pln"> sumAll</span><span class="pun">(...</span><span class="pln">args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ‫اسم المصفوفة هو args</span><span class="pln">
  let sum </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">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let arg of args</span><span class="pun">)</span><span class="pln"> sum </span><span class="pun">+=</span><span class="pln"> arg</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> sum</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> sumAll</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"> </span><span class="com">// 1</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> sumAll</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="pun">);</span><span class="pln"> </span><span class="com">// 3</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> sumAll</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="pun">);</span><span class="pln"> </span><span class="com">// 6</span></pre>

<p>
	يمكن لو أردنا أن نأخذ المُعاملات الأولى في متغيّرات ونجمع البقية فقط.
</p>

<p>
	هنا نأخذ الوسيطين الأوليين في متغيرات والباقي نرميه في المصفوفة <code>‎titles‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_11" style="">
<span class="kwd">function</span><span class="pln"> showName</span><span class="pun">(</span><span class="pln">firstName</span><span class="pun">,</span><span class="pln"> lastName</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">titles</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> firstName </span><span class="pun">+</span><span class="pln"> </span><span class="str">' '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> lastName </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Julius Caesar</span><span class="pln">

  </span><span class="com">// ‫الباقي نضعه في مصفوفة الأسماء titles</span><span class="pln">
  </span><span class="com">// ‫مثلًا titles = ["Consul", "Imperator"]‎</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> titles</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="com">// Consul</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> titles</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"> </span><span class="com">// Imperator</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> titles</span><span class="pun">.</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

showName</span><span class="pun">(</span><span class="str">"Julius"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Caesar"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Consul"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Imperator"</span><span class="pun">);</span></pre>

<p>
	<strong>يجب أن تُترك المُعاملات البقية إلى النهاية</strong> تجمع المُعاملات البقية كلّ الوُسطاء التي بقيت. وبهذا فالآتي ليس منطقيًا وسيتسبّب بخطأ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_13" style="">
<span class="kwd">function</span><span class="pln"> f</span><span class="pun">(</span><span class="pln">arg1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">rest</span><span class="pun">,</span><span class="pln"> arg2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ‫الوسيط arg2 بعد ...البقية؟!</span><span class="pln">
  </span><span class="com">// خطأ</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يجب أن يكون <code>‎...rest‎</code> الأخير دومًا.
</p>

<h2>
	متغير الوسطاء arguments
</h2>

<p>
	هناك كائن آخر شبيه بالمصفوفات يُدعى <code>‎arguments‎</code> ويحتوي على كلّ الوُسطاء حسب ترتيب فهارسها.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_15" style="">
<span class="kwd">function</span><span class="pln"> showName</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> arguments</span><span class="pun">.</span><span class="pln">length </span><span class="pun">);</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> arguments</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">
  alert</span><span class="pun">(</span><span class="pln"> arguments</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">

  </span><span class="com">// المصفوفة مُتعدَّدة</span><span class="pln">
  </span><span class="com">// for(let arg of arguments) alert(arg);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// ‫تعرض: 2, Julius, Caesar</span><span class="pln">
showName</span><span class="pun">(</span><span class="str">"Julius"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Caesar"</span><span class="pun">);</span><span class="pln">

</span><span class="com">// ‫تعرض: 1, Ilya, undefined (ما من مُعطى ثانٍ)</span><span class="pln">
showName</span><span class="pun">(</span><span class="str">"Ilya"</span><span class="pun">);</span></pre>

<p>
	قديمًا لم تكن المُعاملات البقية موجودة في اللغة ولم يكن لدينا سوى استعمال <code>‎arguments‎</code> لنجلب كلّ مُعاملات الدالة. وما زالت تعمل الطريقة إلى يومنا هذا ويمكن أن تراها في الشيفرات القديمة.
</p>

<p>
	ولكن السلبية هنا هي أنّ <code>‎arguments‎</code> ليست مصفوفة (على الرغم من أنّها شبيهة بالمصفوفات ومُتعدّدة). بهذا لا تدعم توابِع المصفوفات فلا ينفع أن نستدعي عليها <code>‎arguments.map(...)‎</code> مثلًا.
</p>

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

<p>
	لهذا متى ما احتجنا إلى ميزة كهذه، فالأفضل استعمال المُعاملات البقية بدلًا من <code>‎arguments‎</code>.
</p>

<p>
	<strong>ليس للدوال السهمية <code>‎"arguments"‎</code></strong> لو حاولت الوصول إلى كائن الوُسطاء <code>‎arguments‎</code> من داخل الدالة السهمية، فستستلم الناتج من الدالة «الطبيعية» الخارجية. إليك مثالًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_17" style="">
<span class="kwd">function</span><span class="pln"> f</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let showArg </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"> alert</span><span class="pun">(</span><span class="pln">arguments</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]);</span><span class="pln">
  showArg</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

f</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span></pre>

<p>
	كما نذكر فليس للدوال السهمية قيمة <code>‎this‎</code> تخصّها، أمّا الآن صرنا نعلم بأنّ ليس لها كائن <code>‎arguments‎</code> أيضًا.
</p>

<h2>
	مُعامل التوزيع
</h2>

<p>
	رأينا كيف نأخذ مصفوفة من قائمة من المُعطيات.
</p>

<p>
	ولكن ماذا لو أردنا العكس من ذلك؟
</p>

<p>
	فمثلًا لنقل أردنا استعمال الدالة المبنية في اللغة Math.max والتي تُعيد أكبر عدد من القائمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_19" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="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">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5</span></pre>

<p>
	لنقل أنّ لدينا المصفوفة <code>‎[3, 5, 1]‎</code>. كيف نستدعي <code>‎Math.max‎</code> عليها؟
</p>

<p>
	لا ينفع تمريرها «كما هي» لأنّ <code>‎Math.max‎</code> يتوقّع قائمةً بالوُسطاء العددية لا مصفوفة واحدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_21" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</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">1</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// NaN</span></pre>

<p>
	وطبعًا لا يمكن أن نفكّ عناصر القائمة يدويًا في الشيفرة <code>‎Math.max(arr[0], arr[1], arr[2])‎</code> لأنّنا في حالات لا نعرف كم من عنصر هناك أصلًا. وما إن يتنفّذ السكربت يمكن أن يكون فيه أكبر مما كتبناه أو حتّى لا شيء أصلًا، وسنحصد لاحقًا ما جنته هذه الشيفرة.
</p>

<p>
	عاش مُنقذنا <em>مُعامل التوزيع</em>! عاش عاش عاش! من بعيد نراه مشابهًا تمامًا للمُعاملات البقية، كما ويستعمل <code>‎...‎</code>، إلّا أنّ وظيفته هي العكس تمامًا.
</p>

<p>
	فحين نستعمل <code>‎‎...arr‎</code> في استدعاء الدالة، «يتوسّع» الكائن المُتعدَّد <code>‎...arr‎</code> إلى قائمة من الوُسطاء.
</p>

<p>
	فمثلًا نعود إلى <code>‎Math.max‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_25" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</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">1</span><span class="pun">];</span><span class="pln">

</span><span class="com">// (يحوّل التوزيع المصفوفة إلى قائمة من الوُسطاء)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(...</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5</span></pre>

<p>
	يمكن أيضًا أن نمرّر أكثر من مُتعدَّد واحد بهذه الطريقة:
</p>

<pre class="ipsCode">
let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];

alert( Math.max(...arr1, ...arr2) ); // 8
</pre>

<p>
	أو حتّى ندمج مُعامل التوزيع مع القيم العادية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_27" style="">
<span class="pln">let arr1 </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="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">];</span><span class="pln">
let arr2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">8</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="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">arr1</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">arr2</span><span class="pun">,</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="com">// 25</span></pre>

<p>
	كما يمكن أن نستعمل مُعامل التوزيعة لدمج المصفوفات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_29" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</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">1</span><span class="pun">];</span><span class="pln">
let arr2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pun">];</span><span class="pln">

let merged </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="pun">...</span><span class="pln">arr</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">arr2</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">merged</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫0,3,5,1,2,8,9,15 (0 ثمّ arr ثمّ 2 ثمّ arr2)</span></pre>

<p>
	استعملنا في الأمثلة أعلاه مصفوفة لنشرح مُعامل التوزيع، إلّا أنّ المُتعدَّدات أيًا كانت تنفع أيضًا.
</p>

<p>
	فمثلًا نستعمل هنا مُعامل التوزيع لنحوّل السلسلة النصية إلى مصفوفة محارف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_31" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">[...</span><span class="pln">str</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// H,e,l,l,o</span></pre>

<p>
	يستعمل مُعامل التوزيع هذا داخليًا المُعدِّدات لجمع العناصر، كما تفعل حلقة <code>‎for..of‎</code>.
</p>

<p>
	لذا لو استلمت <code>‎for..of‎</code> سلسلةً نصيّة فتُعيد لنا المحارف وتصير <code>‎‎...str‎</code> بالقيمة <code>‎"H","e","l","l","o"‎</code>. وهكذا تُمرّر قائمة المحارف إلى مُهيّئ المصفوفة <code>‎[...str]‎</code>.
</p>

<p>
	يمكننا أيضًا لهذه المهمة استعمال <code>‎Array.from‎</code> إذ أنّه يحوّل المُتعدَّد (مثل السلاسل النصية) إلى مصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1837_33" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// ‫يُحوّل Array.from المُتعدَّد إلى مصفوفة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">str</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// H,e,l,l,o</span></pre>

<p>
	ناتجه هو ذات ناتج <code>‎[‎...str]‎</code>.
</p>

<p>
	ولكن… هناك فرق ضئيل بين <code>‎Array.from(obj)‎</code> و<code>‎[...obj]‎</code>:
</p>

<ul>
<li>
		يعمل <code>‎Array.from‎</code> على الشبيهات بالمصفوفات والمُتعدَّدات.
	</li>
	<li>
		ويعمل مُعامل التوزيع على المُتعدَّدات فقط لا غير.
	</li>
</ul>
<p>
	لذا لو أردت تحويل شيء إلى مصفوفة فالتابِع <code>‎Array.from‎</code> أكثر استعمالًا وشيوعًا.
</p>

<h2>
	ملخص
</h2>

<p>
	متى رأينا <code>‎"..."‎</code> في الشيفرة نعرف أنّه إمّا المُعاملات البقية وأمّا مُعامل التوزيع.
</p>

<p>
	إليك طريقة بسيطة للتفريق بينهما:
</p>

<ul>
<li>
		حين ترى <code>‎...‎</code> موجودة في نهاية مُعاملات الدالة فهي «المُعاملات البقية» وستجمع بقية قائمة الوُسطاء في مصفوفة.
	</li>
	<li>
		وحين ترى <code>‎...‎</code> في استدعاء دالة أو ما شابهه فهو «مُعامل توزيع» يوسّع المصفوفة إلى قائمة.
	</li>
</ul>
<p>
	طُرق الاستعمال:
</p>

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

<p>
	يمكنك أيضًا أن ترى كل وُسطاء استدعاء الدالة «بالطريقة القديمة» <code>‎arguments‎</code> وهو كائن مُتعدَّد شبيه بالمصفوفات.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/rest-parameters-spread" rel="external nofollow">Rest parameters and spread syntax</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">871</guid><pubDate>Thu, 09 Apr 2020 18:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x648;&#x62F; recursion &#x648;&#x627;&#x644;&#x645;&#x643;&#x62F;&#x633; stack &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF-recursion-%D9%88%D8%A7%D9%84%D9%85%D9%83%D8%AF%D8%B3-stack-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r870/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_04/44.jpg.5d1d6e22ded47993daf62e5a66088e37.jpg" /></p>

<p>
	فلنعد الآن إلى الدوال ونرى أمرها بتمعّن وتعمّق أكثر. سنتكلم أولًا عن <em>التعاود</em> (Rescursion).
</p>

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

<p>
	يُعدّ التعاود (Rescursion) نمطًا برمجيًا نستعمله حين يمكن تقسيم المهمة الكبيرة جدًا إلى مهام أبسط منها متشابهة، أو حين يمكن تبسيط المهمة الواحدة إلى عملية بعضها بسيط وآخر يتشابه بين بعضه، أو نستعمله (كما سنرى قريبًا) للتعامل مع أنواعٍ محدّدة من بنى البيانات.
</p>

<p>
	يمكن للدالة حين تحاول إجراء مهمّة ما نداءَ دوال أخرى. أحيانًا يمكن أن تنادي تلك الدالة <em>نفسها</em> ثانيةً. هذا ما ندعوه <em>بالتعاود</em>.
</p>

<h2>
	نهجان في التطوير
</h2>

<p>
	لنبدأ بما هو أبسط. لنكتب دالة <code>‎pow(x, n)‎</code> ترفع <code>‎x‎</code> إلى الأسّ الطبيعي <code>‎n‎</code>. بعبارة أخرى، تضرب <code>‎x‎</code> بنفسه <code>‎n‎</code> مرّة.
</p>

<pre class="ipsCode">
pow(2, 2) = 4
pow(2, 3) = 8
pow(2, 4) = 16
</pre>

<p>
	يمكننا تنفيذ هذه الدالة بطريقتين اثنتين.
</p>

<ul>
<li>
		التفكير بالتكرار: حلقة <code>‎for‎</code>:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_8" style="">
<span class="kwd">function</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">x</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">
  let result </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">// ‫نضرب الناتج في x - ‏n مرّة داخل الحلقة</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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">
    result </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"> result</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> pow</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 8</span></pre>

<p>
	 
</p>

<ul>
<li>
		التفكير بالتعاود: تبسيط المهمة ونداء «الذات»:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_10" style="">
<span class="kwd">function</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">x</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">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</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">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> x </span><span class="pun">*</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> pow</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 8</span></pre>

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

<p>
	حين تُستدعى <code>‎pow(x, n)‎</code> تنقسم عملية التنفيذ إلى فرعين:
</p>

<pre class="ipsCode">
              if n==1  = x
             /
pow(x, n) =
             \       
              else     = x * pow(x, n - 1)
</pre>

<ol>
<li>
		حين <code>‎n == 1‎</code>، نرى كل شيء كالعادة. نسمّي تلك الحالة <em>بأساس</em> التعاود، لأنها تُعطينا الناتج البديهي مباشرة: <code>‎pow(x, 1)‎</code> تساوي <code>‎x‎</code>.
	</li>
	<li>
		عدى تلك فيمكننا تمثيل <code>‎pow(x, n)‎</code> على أنها <code>‎x * pow(x, n - 1)‎</code>. يمكنك رياضيًا كتابة <code>x&lt;sup&gt;n&lt;/sup&gt; = x * x&lt;sup&gt;n-1&lt;/sup&gt;</code>. نسمّي هذه <em>خطوة تعاودية</em>: فنعدّل مهمة الأس الكبيرة لتصير عملية أبسط (الضرب في <code>‎x‎</code>) ونستعمل استدعاءً أبسط لمهمة الأس (<code>‎pow‎</code> ولكن <code>‎n‎</code> أقل). في الخطوات اللاحقة تصير أبسط وأبسط إلى أن تصل <code>‎n‎</code> إلى <code>‎1‎</code>.
	</li>
</ol>
<p>
	يمكن أيضًا أن نقول بأن <code>‎pow‎</code> <em>تستدعي نفسها تعاوديًا</em> حتى تكون <code>‎n == 1‎</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37831" href="https://academy.hsoub.com/uploads/monthly_2020_04/recursion-pow.png.d6f09723944cdd59ac9716fc909bbea4.png" rel=""><img alt="recursion-pow.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37831" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/recursion-pow.png.d6f09723944cdd59ac9716fc909bbea4.png"></a>
</p>

<p>
	فمثلًا كي نحسب قيمة <code>‎pow(2, 4)‎</code> على التعاود إجراء هذه المهام:
</p>

<pre class="ipsCode" id="ips_uid_2895_14">
1. pow(2, 4) = 2 * pow(2, 3)
2. pow(2, 3) = 2 * pow(2, 2)
3. pow(2, 2) = 2 * pow(2, 1)
4. pow(2, 1) = 2
</pre>

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

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

<p>
	يمكننا هنا مثلًا إعادة كتابة نفس الشيفرة ولكن باستعمال المُعامل الشرطي <code>‎?‎</code> بدل <code>‎if‎</code> لتصير <code>‎pow(x, n)‎</code> أقصر أكثر وتبقى مقروءةً لنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_16" style="">
<span class="kwd">function</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">x</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">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </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">x </span><span class="pun">*</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">));</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُسمّى أقصى عدد من الاستدعاءات المتداخلة (بما في ذلك أول استدعاء) <em>بعمق التعاود</em> (Rescursion Depth). في حالتنا هنا سيكون هذا العمق <code>‎n‎</code>.
</p>

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

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

<h2>
	سياق التنفيذ والمكدس
</h2>

<p>
	لنرى الآن كيف يعمل التعاود أصلًا، ولذلك لا بدّ من أن نرى ما خلف كواليس الدوال هذه.
</p>

<p>
	تُخزّن المعلومات حول عملية تنفيذ الدالة (حين تعمل) في <em>سياقها التنفيذي</em> (execution context). يُعدّ <a href="https://tc39.github.io/ecma262/#sec-execution-contexts" rel="external nofollow">سياق التنفيذ</a> بنيةَ بيانات داخلية تحوي التفاصيل التي تخصّ عملية تنفيذ الدالة: إلى أين وصلت الآن؟ ما المتغيرات الحالية؟ ما قيمة <code>‎this‎</code> (لا نستعملها هنا) وتفاصيل أخرى داخلية. لكلّ استدعاء دالة سياق تنفيذي واحد مرتبط بها.
</p>

<p>
	حين تستدعي الدالة دوال أخرى متداخلة، يحدث:
</p>

<ul>
<li>
		تتوقف الدالة الحالية مؤقتًا.
	</li>
	<li>
		يُحفظ سياق التنفيذ المرتبط بها في بنية بيانات خاصّة تسمى <em>مكدس سياق التنفيذ</em> <em>execution context stack</em>.
	</li>
	<li>
		يتنفّذ الاستدعاء المتداخل.
	</li>
	<li>
		ما إن ينتهي، يجلب المحرّك التنفيذ القديم ذاك من المكدس، وتواصل الدالة الخارجية عملها حيث توقفت.
	</li>
</ul>
<p>
	لنرى ما يحدث أثناء استدعاء <code>‎pow(2, 3)‎</code>.
</p>

<h3>
	pow(2, 3)‎
</h3>

<p>
	يخزّن سياق التنفيذ (في بداية استدعاء <code>‎pow(2, 3)‎</code>) المتغيرات هذه: <code>‎x = 2, n = 3‎</code> وأنّ سير التنفيذ هو في السطر رقم <code>‎1‎</code> من الدالة.
</p>

<p>
	يمكن أن نرسمه هكذا:
</p>

<ul class="function-execution-context-list">
<li>
		<span class="function-execution-context">السياق: { x: 2, n: 3, عند السطر 1 }</span> <span class="function-execution-context-call">pow(2, 3)</span>‎
	</li>
</ul>
<style type="text/css">
.function-execution-context {
   border: 1px solid black;
   font-family: 'DejaVu Sans Mono', 'Lucida Console', 'Menlo', 'Monaco', monospace;
   padding: 4px 6px;
   margin: 0 4px;
}
.function-execution-context-call {
   color: gray;
}</style>
<p>
	هذا ما يجري حين يبدأ تنفيذ الدالة. بعد أن يصير الشرط <code>‎n == 1‎</code> خطأً، ينتقل سير التنفيذ إلى الفرع الثاني من الإفادة <code>‎if‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_18" style="">
<span class="kwd">function</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">x</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">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</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">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> x </span><span class="pun">*</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> pow</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	ما زالت المتغيرات كما هي، ولكن السطر تغيّر. بذلك يصير السياق الآن:
</p>

<ul class="function-execution-context-list">
<li>
		<span class="function-execution-context">السياق: { x: 2, n: 3, عند السطر 5 }</span> <span class="function-execution-context-call">pow(2, 3)</span>‎
	</li>
</ul>
<p>
	علينا لحساب <code>‎x * pow(x, n - 1)‎</code> استدعاء <code>‎pow‎</code> فرعيًا بالوُسطاء الجديدة <code>‎pow(2, 2)‎</code>.
</p>

<h3>
	pow(2, 2)‎
</h3>

<p>
	كي يحدث الاستدعاء المتداخل، يتذكّر محرّك جافاسكربت سياق التنفيذ الحالي داخل <em>مكدس سياق التنفيذ</em>.
</p>

<p>
	هنا نستدعي ذات الدالة <code>‎pow‎</code>، ولكن ذلك لا يهم إذ أنّ العملية هي ذاتها لكلّ الدوال:
</p>

<ol>
<li>
		«يتذكّر المحرّك» السياقَ الحالي أعلى المكدس.
	</li>
	<li>
		يَصنع سياقًا جديدًا للاستدعاء الفرعي.
	</li>
	<li>
		متى انتهى الاستدعاء الفرعي يُطرح (pop) السياق السابق من المكدس ويتواصل التنفيذ.
	</li>
</ol>
<p>
	هذا مكدس السياق حين ندخل الاستدعاء الفرعي <code>‎pow(2, 2)‎</code>:
</p>

<ul class="function-execution-context-list">
<li>
		<span class="function-execution-context">السياق: { x: 2, n: 2, عند السطر 1 }</span> <span class="function-execution-context-call">pow(2, 2)</span>‎
	</li>
	<li>
		<span class="function-execution-context">السياق: { x: 2, n: 3, عند السطر 5 }</span> <span class="function-execution-context-call">pow(2, 3)</span>‎
	</li>
</ul>
<p>
	سياق التنفيذ الحالي والجديد هو الأعلى (بالخط الثخين) وأسفله السياقات التي تذكّرها المحرّك سابقًا.
</p>

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

<p>
	<strong>ملاحظة:</strong> نرى في الصورة أنّا استعملنا كلمة «سطر» إذ ليس في المثال إلّا استدعاءً فرعيًا واحدًا في السطر، ولكن يمكن أن تحتوي الشيفرات ذات السطر الواحد (بصفة عامة) على أكثر من استدعاءً فرعيًا، هكذا: <code>‎pow(…) + pow(…) + somethingElse(…)‎</code>.
</p>

<p>
	لذا سنكون أدقّ لو قلنا بأن عملية التنفيذ تتواصل «بعد الاستدعاء الفرعي مباشرةً».
</p>

<h3>
	pow(2, 1)‎
</h3>

<p>
	تتكرّر العملية: يُصنع استدعاء فرعي جديد في السطر <code>‎5‎</code> بالوسطاء الجديدة <code>‎x=2‎</code> و <code>‎n=1‎</code>.
</p>

<p>
	صنعنا سياقًا جديدًا، إذًا ندفع (push) الأخير أعلى المكدس:
</p>

<ul class="function-execution-context-list">
<li>
		<span class="function-execution-context">السياق: { x: 2, n: 1, عند السطر 1 }</span> <span class="function-execution-context-call">pow(2, 1)</span>‎
	</li>
	<li>
		<span class="function-execution-context">السياق: { x: 2, n: 2, عند السطر 5 }</span> <span class="function-execution-context-call">pow(2, 2)</span>‎
	</li>
	<li>
		<span class="function-execution-context">السياق: { x: 2, n: 3, عند السطر 5 }</span> <span class="function-execution-context-call">pow(2, 3)</span>‎
	</li>
</ul>
<p>
	الآن هناك سياقين اثنين قديمين، وواحد يعمل للاستدعاء <code>‎pow(2, 1)‎</code>.
</p>

<h3>
	المخرج
</h3>

<p>
	نرى الشرط <code>‎n == 1‎</code> صحيحًا أثناء تنفيذ الاستدعاء <code>‎pow(2, 1)‎</code> (عكس ما سبقه من مرّات)، إذًا فالفرع الأول من إفادة <code>‎if‎</code> سيعمل هنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_20" style="">
<span class="kwd">function</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">x</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">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</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">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> x </span><span class="pun">*</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا استدعاءات متداخلة من هنا، بذلك تنتهي الدالة وتُعيد <code>‎2‎</code>.
</p>

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

<ul class="function-execution-context-list">
<li>
		<span class="function-execution-context">السياق: { x: 2, n: 2, عند السطر 5 }</span> <span class="function-execution-context-call">pow(2, 2)</span>‎
	</li>
	<li>
		<span class="function-execution-context">السياق: { x: 2, n: 3, عند السطر 5 }</span> <span class="function-execution-context-call">pow(2, 3)</span>‎
	</li>
</ul>
<p>
	يتواصل تنفيذ الاستدعاء <code>‎pow(2, 2)‎</code>، وفيه ناتج الاستدعاء الفرعي <code>‎pow(2, 1)‎</code> لذا يُنهي أيضًا تنفيذ <code>‎x * pow(x, n - 1)‎</code> فيُعيد <code>‎4‎</code>.
</p>

<p>
	بعدها يستعيد المحرّك السياقَ السابق:
</p>

<ul class="function-execution-context-list">
<li>
		<span class="function-execution-context">السياق: { x: 2, n: 3, عند السطر 5 }</span> <span class="function-execution-context-call">pow(2, 3)</span>‎
	</li>
</ul>
<p>
	وحين ينتهي، يكون عندنا ناتج <code>‎pow(2, 3) = 8‎</code>.
</p>

<p>
	عمق التعاود في هذه الحالة هو: <strong>3</strong>.
</p>

<p>
	كما نرى في الصور أعلاه فعمق التعاود يساوي أقصى عدد من السياقات في المكدس.
</p>

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

<p>
	خوارزميات الحلقات والتكرار أفضل من حيث استعمال الذاكرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_23" style="">
<span class="kwd">function</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">x</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">
  let result </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">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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">
    result </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"> result</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تستعمل دالة <code>‎pow‎</code> المتكرّرة سياقًا واحدًا تغيّر فيه المتغيران <code>‎i‎</code> و<code>‎result‎</code> أثناء عملها، كما وأنّ احتياجاتها للذاكرة قليلة وثابتة ولا تعتمد على قيمة <code>‎n‎</code>.
</p>

<p>
	<strong>يمكن كتابة التعاودات أيًا كانت بصيغة الحلقات، وغالبًا ما تكون تلك الحلقات أفضل أداءً.</strong>
</p>

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

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

<h2>
	مسح الأشجار تعاوديًا
</h2>

<p>
	مسح الأشجار تعاوديًا <em>Recursive Traversal</em> هو تطبيق آخر عن روعة التعاود.
</p>

<p>
	لنقل بأنّ لدينا شركة ويمكن أن نمثّل بنية موظّفيها في هذا الكائن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_25" style="">
<span class="pln">let company </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sales</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">'John'</span><span class="pun">,</span><span class="pln">
    salary</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1000</span><span class="pln">
  </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">'Alice'</span><span class="pun">,</span><span class="pln">
    salary</span><span class="pun">:</span><span class="pln"> </span><span class="lit">600</span><span class="pln">
  </span><span class="pun">}],</span><span class="pln">

  development</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sites</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">'Peter'</span><span class="pun">,</span><span class="pln">
      salary</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2000</span><span class="pln">
    </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">'Alex'</span><span class="pun">,</span><span class="pln">
      salary</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1800</span><span class="pln">
    </span><span class="pun">}],</span><span class="pln">

    internals</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">'Jack'</span><span class="pun">,</span><span class="pln">
      salary</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1300</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>‎sales‎</code> عاملين اثنين: John وAlice.
		</p>
	</li>
	<li>
		<p>
			أو أن ينقسم القسم إلى أقسام فرعية، مثل قسم التطوير <code>‎development‎</code> له فرعان: تطوير المواقع <code>‎sites‎</code> والبرمجيات الداخلية <code>‎internals‎</code>. ولكلّ من الفرعين موظفين منفصلين.
		</p>
	</li>
	<li>
		<p>
			يمكن أيضًا أن يكبُر القسم الفرعي ويصير فروع من القسم الفرعي (أي «فِرَق»).
		</p>

		<p>
			مثلًا قسم المبيعات <code>‎sites‎</code> سيتطوّر ويتحسّن وينقسم مستقبلًا إلى فرعين <code>‎siteA‎</code> و <code>‎siteB‎</code>. وبعدها ربما (لو عمل فريق التسويق بجدّ) ينقسم أكثر أيضًا. طبعًا هذا تخيّل فقط وليس في الصورة تلك.
		</p>
	</li>
</ul>
<p>
	الآن، ماذا لو أردنا دالة تعطينا مجموع كل الرواتب؟ كيف السبيل؟
</p>

<p>
	لو جرّبنا بالتكرار فسيكون أمرًا عسيرًا إذ أنّ البنية ليست ببسيطة. أول فكرة على البال هي حلقة <code>‎for‎</code> تمرّ على الشركة <code>‎company‎</code> وداخلها حلقات فرعية على الأقسام بالمستوى الأول. ولكن هكذا سنحتاج حلقات فرعية متداخلة أيضًا لتمرّ على الموظفين في الأقسام بالمستوى الثاني مثل قسم <code>‎sites‎</code>… وبعدها حلقات أخرى داخل تلك فوقها للأقسام بالمستوى الثالث إن عمل فريق التسويق كما يجب… لو وضعنا 3-4 من هذه الحلقات الفرعية المتداخلة في شيفرة لتعمل جولة مسح على كائن واحد، فستنتج لنا شيفرة قبيحة حقًا.
</p>

<p>
	لنجرّب التعاود الآن.
</p>

<p>
	كما رأينا، حين تُلاقي الدالة قسمًا عليها جمع رواتبه، تواجه حالتين اثنتين:
</p>

<ol>
<li>
		إمّا يكون قسمًا «بسيطًا» فيه <em>مصفوفة</em> من الناس، وهكذا تجمع رواتبهم في حلقة بسيطة.
	</li>
	<li>
		أو تجد <em>كائنًا</em> فيه <code>‎N‎</code> من الأقسام الفرعية، حينها تصنع <code>‎N‎</code> من الاستدعاءات المتعاودة لتحصي مجموع كلّ قسم فرعي وتدمج النتائج كلها.
	</li>
</ol>
<p>
	الحالة الأولى هي أساس التعاود، أي عملنا العادي حين نستلم مصفوفة.
</p>

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

<p>
	ربّما… يكون أسهل لو قرأت الخوارزمية من الشيفرة ذاتها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_27" style="">
<span class="com">// الكائن كما هو، ضغطناه لألا نُطيل القصة فقط</span><span class="pln">
let company </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  sales</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">'John'</span><span class="pun">,</span><span class="pln"> salary</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">name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Alice'</span><span class="pun">,</span><span class="pln"> salary</span><span class="pun">:</span><span class="pln"> </span><span class="lit">600</span><span class="pln"> </span><span class="pun">}],</span><span class="pln">
  development</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sites</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">'Peter'</span><span class="pun">,</span><span class="pln"> salary</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2000</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">'Alex'</span><span class="pun">,</span><span class="pln"> salary</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1800</span><span class="pln"> </span><span class="pun">}],</span><span class="pln">
    internals</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">'Jack'</span><span class="pun">,</span><span class="pln"> salary</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1300</span><span class="pun">}]</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// الدالة التي ستنفّذ هذا العمل</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> sumSalaries</span><span class="pun">(</span><span class="pln">department</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="typ">Array</span><span class="pun">.</span><span class="pln">isArray</span><span class="pun">(</span><span class="pln">department</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ‫حالة (1)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> department</span><span class="pun">.</span><span class="pln">reduce</span><span class="pun">((</span><span class="pln">prev</span><span class="pun">,</span><span class="pln"> current</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> prev </span><span class="pun">+</span><span class="pln"> current</span><span class="pun">.</span><span class="pln">salary</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">// نجمع عناصر المصفوفة</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ‫حالة (2)</span><span class="pln">
    let sum </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">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let subdep of </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">values</span><span class="pun">(</span><span class="pln">department</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// نستدعي الأقسام الفرعية تعاوديًا، ونجمع النتائج</span><span class="pln">
      sum </span><span class="pun">+=</span><span class="pln"> sumSalaries</span><span class="pun">(</span><span class="pln">subdep</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"> sum</span><span class="pun">;</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="pln">sumSalaries</span><span class="pun">(</span><span class="pln">company</span><span class="pun">));</span><span class="pln"> </span><span class="com">// 6700</span></pre>

<p>
	الشيفرة قصيرة وسهل فهمها (كما هو أملي). هنا تظهر قوّة التعاود، فسيعمل على أيّ مستوى من الأقسام الفرعية المتداخلة.
</p>

<p>
	إليك رسمة توضّح الاستدعاءات:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37832" href="https://academy.hsoub.com/uploads/monthly_2020_04/recursive-salaries.png.1addc3e4802e2f70a6a8a07628d1f63c.png" rel=""><img alt="recursive-salaries.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37832" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/recursive-salaries.png.1addc3e4802e2f70a6a8a07628d1f63c.png"></a>
</p>

<p>
	الفكرة بسيطة للغاية: لو كان كائنًا <code>‎{...}‎</code>، نستعمل الاستدعاءات الفرعية، ولو كانت مصفوفات <code>‎[...]‎</code> هي آخر «أوراق» شجرة التعاود، فتعطينا الناتج مباشرةً.
</p>

<p>
	لاحظ كيف أنّ الشيفرة تستعمل مزايا ذكيّة ناقشناها سابقًا:
</p>

<p>
	التابِع <code>‎arr.reduce‎</code> في الفصل «توابِع المصفوفات» لنجمع الرواتب.
</p>

<ul>
<li>
		الحلقة <code>‎for(val of Object.values(obj))‎</code> للمرور على قيم الكائن إذ يُعيد التابِع <code>‎Object.values‎</code> مصفوفة بالقيم.
	</li>
</ul>
<h2>
	بنى التعاود
</h2>

<p>
	بنية البيانات التعاودية (أيّ التي يحدّد أساسها التعاود) هي بنية تكرّر نفسها على أجزاء منفصلة.
</p>

<p>
	رأينا لتوّنا مثالًا عن هذه البنية: بنية الشركة أعلاه.
</p>

<p>
	<em>القسم</em> في الشركة هو إمّا:
</p>

<ul>
<li>
		مصفوفة من الناس.
	</li>
	<li>
		أو كائنًا فيه <em>أقسام أخرى</em>.
	</li>
</ul>
<p>
	لو كنت مطوّر وِب فالأمثلة التي تعرفها وتُدركها هي مستندات HTML وXML.
</p>

<p>
	ففي مستندات HTML، يمكن أن يحتوي <em>وسم HTML</em> على قائمة من:
</p>

<ul>
<li>
		أجزاء من نصوص.
	</li>
	<li>
		تعليقات HTML.
	</li>
	<li>
		<em>وسوم HTML</em> أخرى (أي ما يمكن أن يحتوي على أجزاء من نصوص أو تعليقات أو وسوم أخرى وهكذا).
	</li>
</ul>
<p>
	وهذا ما نسمّيه بالبنى التعاوديّة.
</p>

<p>
	لنفهم التعاود أكثر سنشرح بنية تعاود أخرى تسمّى «القوائم المترابطة» (Linked List). يمكن أن تكون هذه القوائم أحيانًا بديلًا أفضل موازنةً بالمصفوفات.
</p>

<h3>
	القوائم المترابطة
</h3>

<p>
	لنقل بأنّا نريد تخزين قائمة كائنات مرتّبة.
</p>

<p>
	ستصنع مصفوفة كالعادة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_29" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">obj1</span><span class="pun">,</span><span class="pln"> obj2</span><span class="pun">,</span><span class="pln"> obj3</span><span class="pun">];</span></pre>

<p>
	ولكن… هناك مشكلة تخصّ المصفوفات. عمليات «حذف العنصر» و«إدراج العنصر» مُكلفة. فمثلًا على عملية <code>‎arr.unshift(obj)‎</code> إعادة ترقيم كلّ العناصر للكائن الجديد <code>‎obj‎</code>، ولو كانت المصفوفة كبيرة فستأخذ العملية وقتًا طويلًا. الأمر نفسه ينطبق لعملية <code>‎arr.shift()‎</code>.
</p>

<p>
	التعديلات على بنية البيانات (التي لا تحتاج إلى إعادة الترقيم بالجملة) هي تلك التي تؤثّر على نهاية المصفوفة: <code>‎arr.push/pop‎</code>. لذا يمكن أن تكون المصفوفة بطيئة حقًا لو كانت الطوابير طويلة حين نعمل مع المصفوفات من عناصرها الأولى.
</p>

<p>
	يمكننا عوض ذلك استعمال بنية بيانات أخرى لو أردنا إدخال البيانات وحذفها سريعًا. تُدعى هذه البنية <a href="https://ar.wikipedia.org/wiki/%D9%82%D8%A7%D8%A6%D9%85%D8%A9_%D9%85%D8%AA%D8%B5%D9%84%D8%A9" rel="external nofollow">بالقائمة المترابطة</a>.
</p>

<p>
	يُعرّف <em>عنصر القائمة المترابطة</em> تعاوديًا على أنّه كائن فيه:
</p>

<ul>
<li>
		قيمة <code>‎value‎</code>.
	</li>
	<li>
		خاصية «التالي» <code>‎next‎</code> تُشير إلى <em>عنصر القائمة المترابطة</em> التالي أو إلى <code>‎null‎</code> لو كانت هذه نهاية القائمة.
	</li>
</ul>
<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_31" style="">
<span class="pln">let list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
      next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
        next</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	إليك التمثيل البصري لهذه القائمة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37830" href="https://academy.hsoub.com/uploads/monthly_2020_04/linked-list.png.0f1bbe1b8ab1570c42612e71cb42d02f.png" rel=""><img alt="linked-list.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37830" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/linked-list.png.0f1bbe1b8ab1570c42612e71cb42d02f.png"></a>
</p>

<p>
	هذه شيفرة أخرى لنصنع القائمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_33" style="">
<span class="pln">let list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
list</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span></pre>

<p>
	هنا نرى بوضوح أكثر كيف أنّ هناك كائنات متعدّدة لكلّ منها خاصية <code>‎value‎</code> وأخرى <code>‎next‎</code> تُشير إلى العنصر بقرب «هذا». متغيّر <code>‎list‎</code> هو أول الكائنات في السلسلة وبهذا لو اتّبعنا إشارات <code>‎next‎</code> بدءًا منها سنصل إلى أيّ عنصر آخر نريد.
</p>

<p>
	يمكننا قسمة القائمة إلى أجزاء عدّة ودمجها لاحقًا لو أردنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_35" style="">
<span class="pln">let secondList </span><span class="pun">=</span><span class="pln"> list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next</span><span class="pun">;</span><span class="pln">
list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37829" href="https://academy.hsoub.com/uploads/monthly_2020_04/linked-list-split.png.b982ddacf3ce9bf2bd8bc55daa0d2817.png" rel=""><img alt="linked-list-split.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37829" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/linked-list-split.png.b982ddacf3ce9bf2bd8bc55daa0d2817.png"></a>
</p>

<p>
	للدمج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_37" style="">
<span class="pln">list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> secondList</span><span class="pun">;</span></pre>

<p>
	وطبعًا يمكننا إدخال العناصر إلى أي مكان وإزالتها من أي مكان.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_39" style="">
<span class="pln">let list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
list</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

</span><span class="com">// نُضيف قيمة جديدة إلى بداية القائمة</span><span class="pln">
list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="str">"new item"</span><span class="pun">,</span><span class="pln"> next</span><span class="pun">:</span><span class="pln"> list </span><span class="pun">};</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37827" href="https://academy.hsoub.com/uploads/monthly_2020_04/linked-list-0.png.53b7f3ffcfd2210e05fe2b67f0e175e1.png" rel=""><img alt="linked-list-0.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37827" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/linked-list-0.png.53b7f3ffcfd2210e05fe2b67f0e175e1.png"></a>
</p>

<p>
	ولنُزيل قيمة من المنتصف نعدّل خاصية <code>‎next‎</code> للكائن الذي يسبق الجديد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_41" style="">
<span class="pln">list</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next</span><span class="pun">;</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37828" href="https://academy.hsoub.com/uploads/monthly_2020_04/linked-list-remove-1.png.0d952fbeb561c2040c75fc2d30c98530.png" rel=""><img alt="linked-list-remove-1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37828" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/linked-list-remove-1.png.0d952fbeb561c2040c75fc2d30c98530.png"></a>
</p>

<p>
	هكذا أجبرنا <code>‎list.next‎</code> بأن «تقفز» فوق <code>‎1‎</code> لتصل <code>‎2‎</code>، بهذا استثنينا القيمة <code>‎1‎</code> من السلسلة. وطالما أنّها ليست مخزّنة في أيّ مكان آخر فستُزال من الذاكرة تلقائيًا.
</p>

<p>
	وعلى عكس المصفوفات فلسنا هنا نُعيد الترقيم بالجملة، أي أنّ إعادة ترتيب العناصر أسهل.
</p>

<p>
	بالطبع فالقوائم ليست أفضل من المصفوفات دومًا وإلا فاستعملناها هي دومًا وما احتجنا المصفوفات أبدًا.
</p>

<p>
	السلبية الأساس هي أنّ الوصول إلى العنصر حسب رقمه ليس سهلًا كما في المصفوفات حيث نستعمل الإشارة المباشرة <code>‎arr[n]‎</code>. ولكن في القوائم علينا البدء من العنصر الأول والانتقال <code>‎N‎</code> مرّة عبر <code>‎next‎</code> لنصل إلى العنصر بالرقم N.
</p>

<p>
	…ولكننا لا نحتاج دومًا إلى هذه العمليات فمثلًا حين نريد طابورًا أو حتّى <a href="https://en.wikipedia.org/wiki/Double-ended_queue" rel="external nofollow">طابورًا متعدّد الطرفين</a> فيجب أن نستعمل بنية مرتّبة تتيح بإضافة/إزالة العناصر من الجهتين بسرعة فائقة، وليس بالضروري أن نعرف ما في وسطها.
</p>

<p>
	يمكننا تحسين القوائم هكذا:
</p>

<ul>
<li>
		إضافة الخاصية <code>‎prev‎</code> مع الخاصية <code>‎next‎</code> للإشارة إلى العنصر السابق، لننتقل وراءً بسهولة أكبر.
	</li>
	<li>
		إضافة متغيّر بالاسم <code>‎tail‎</code> يُشير إلى آخر عنصر من القائمة (وتحديثه متى أضفنا/أزلنا عناصر من النهاية).
	</li>
	<li>
		…يمكن أن تتغيّر بنية البيانات حسب متطلباتنا واحتياجاتنا.
	</li>
</ul>
<h2>
	ملخص
</h2>

<p>
	المصطلحات:
</p>

<ul>
<li>
		<p>
			<em>التعاود</em>* هو مصطلح برمجي يعني استدعاء دالة من داخلها. يمكن استعمال الدوال التعاودية لحلّ المهام المختلفة بطرق ذكية نظيفة.
		</p>

		<p>
			حين تستدعي الدالة نفسها نسمّي ذلك <em>خطوة تعاود</em>. تُعدّ وُسطاء الدالة التي تبسّط المهمّة إلى أقصى درجة بحيث لا تستدعي الدالة أيّ شيء بعدها - تُعدّ <em>أساس</em> التعاود.
		</p>
	</li>
	<li>
		<p>
			بنية البيانات <a href="https://en.wikipedia.org/wiki/Recursive_data_type" rel="external nofollow">التعاودية</a> هي أيّة بنية بيانات تُحدّد نفسها بنفسها.
		</p>

		<p>
			فمثلًا يمكن تعريف القائمة المترابطة على أنّها بنية بيانات تحتوي على كائن يُشير إلى قائمة (أو يُشير إلى null).
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_43" style="">
<span class="pln">list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">,</span><span class="pln"> next </span><span class="pun">-&gt;</span><span class="pln"> list </span><span class="pun">}</span></pre>

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

		<p>
			يمكن استعمال الدوال التعاودية للمرور فيها كما رأينا في مثال <code>‎sumSalary‎</code>.
		</p>
	</li>
</ul>
<p>
	يمكن إعادة كتابة أيّ دالة تعاودية لتصير دالة تستعمل التكرار، وغالبًا ما نفعل هذا لتحسين أداء الدوال. ولكن هناك مهام عديدة يكون الحلّ التعاودي سريعًا كفايةً وأسهل كتابةً ودعمًا.
</p>

<h2>
	تمارين
</h2>

<h3>
	اجمع كلّ الأعداد إلى أن تصل للممرّر
</h3>

<p>
	<em>الأهمية: 5</em>
</p>

<p>
	اكتب الدالة <code>‎sumTo(n)‎</code> التي تجمع الأعداد <code>‎‎1 + 2 + ... + n‎</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_45" style="">
<span class="pln">sumTo</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"> </span><span class="lit">1</span><span class="pln">
sumTo</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </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="lit">1</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
sumTo</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </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="lit">1</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
sumTo</span><span class="pun">(</span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </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="lit">1</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">
sumTo</span><span class="pun">(</span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">99</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="lit">2</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5050</span></pre>

<p>
	اكتب 3 شيفرات:
</p>

<ol>
<li>
		واحدة باستعمال حلقة for.
	</li>
	<li>
		واحدة باستعمال التعاود، إذ أنّ <code>‎sumTo(n) = n + sumTo(n-1)‎</code> طالما <code>‎n &gt; 1‎</code>.
	</li>
	<li>
		واحدة باستعمال <a href="https://ar.wikipedia.org/wiki/%D9%85%D8%AA%D8%AA%D8%A7%D9%84%D9%8A%D8%A9_%D8%AD%D8%B3%D8%A7%D8%A8%D9%8A%D8%A9" rel="external nofollow">المتتاليات الحسابية</a>.
	</li>
</ol>
<p>
	مثال عن الناتج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_47" style="">
<span class="kwd">function</span><span class="pln"> sumTo</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="com">/*... شيفرتك هنا ... */</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> sumTo</span><span class="pun">(</span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5050</span></pre>

<p>
	ملاحظة: أيّ الشيفرات أسرع من الأخرى؟ وأيها أبطأ؟ ولماذا؟
</p>

<p>
	ملاحظة أخرى: هل يمكن أن نستعمل التعاود لحساب <code>‎sumTo(100000)‎</code>؟
</p>

<h4>
	الحل
</h4>

<p>
	الحلّ باستعمال الحلقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_49" style="">
<span class="kwd">function</span><span class="pln"> sumTo</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">
  let sum </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">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> 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">
    sum </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">return</span><span class="pln"> sum</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> sumTo</span><span class="pun">(</span><span class="lit">100</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_2895_51" style="">
<span class="kwd">function</span><span class="pln"> sumTo</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">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </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">return</span><span class="pln"> n </span><span class="pun">+</span><span class="pln"> sumTo</span><span class="pun">(</span><span class="pln">n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> sumTo</span><span class="pun">(</span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	الحلّ باستعمال المعادلة <code>‎sumTo(n) = n*(n+1)/2‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_53" style="">
<span class="kwd">function</span><span class="pln"> sumTo</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">return</span><span class="pln"> n </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </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">

alert</span><span class="pun">(</span><span class="pln"> sumTo</span><span class="pun">(</span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	عن الملاحظة: بالطبع فالمعادلة هي أسرع الحلول فلا تستعمل إلا ثلاث عمليات لكلّ عدد <code>‎n‎</code>. الرياضيات إلى جانبنا هنا!
</p>

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

<p>
	عن الملاحظة الأخرى: تدعم بعض المحرّكات «تحسين نهاية الاستدعاء» (tail call optimization)، ويعني أنّه لو كان الاستدعاء التعاودي هو آخر ما في الدالة (مثلما في الدالة <code>‎sumTo‎</code> أعلاه)، فلن تواصل الدالة الخارجية عملية التنفيذ كي لا يتذكّر المحرّك سياقها التنفيذي. يتيح هذا للمحرّك إزالة قضية الذاكرة بذلك يكون ممكنًا عدّ <code>‎sumTo(100000)‎</code>. ولكن، لو لم يدعم محرّك جافاسكربت هذا النوع من التحسين (وأغلبها لا تدعم) فستواجه الخطأ: تخطّيت أكبر حجم في المكدس، إذ يُفرض -عادةً- حدّ على إجمالي حجم المكدس.
</p>

<h3>
	احسب المضروب
</h3>

<p>
	<em>الأهمية: 4</em>
</p>

<p>
	<a href="https://ar.wikipedia.org/wiki/%D8%B9%D8%A7%D9%85%D9%84%D9%8A" rel="external nofollow">المضروب</a> هو عدد طبيعي مضروب بِ‍ <code>‎«العدد ناقصًا واحد»‎</code> وثمّ بِ‍ <code>‎«العدد ناقصًا اثنين»‎</code> وهكذا إلى أن نصل إلى <code>‎1‎</code>. نكتب مضروب <code>‎n‎</code> بهذا الشكل: <code>n!‎</code>
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_55" style="">
<span class="pln">n</span><span class="pun">!</span><span class="pln"> </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">n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </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="pun">...*</span><span class="lit">1</span></pre>

<p>
	قيم المضاريب لأكثر من <code>‎n‎</code>:
</p>

<pre class="ipsCode">
1! = 1
2! = 2 * 1 = 2
3! = 3 * 2 * 1 = 6
4! = 4 * 3 * 2 * 1 = 24
5! = 5 * 4 * 3 * 2 * 1 = 120
</pre>

<p>
	مهمّتك هي كتابة الدالة <code>‎factorial(n)‎</code> لتحسب <code>‎n!‎‎</code> باستعمال الاستدعاءات التعاودية.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_58" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> factorial</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 120</span></pre>

<p>
	ملاحظة وفائدة: يمكنك كتابة <code>‎n!‎‎</code> هكذا <code>‎n * (n-1)!‎‎</code> مثلًا: <code>‎3! = 3*2! = 3*2*1! = 6</code>
</p>

<h4>
	الحل
</h4>

<p>
	حسب التعريف فيمكن كتابة المضروب <code>‎n!‎‎</code> هكذا <code>‎n * (n-1)!‎</code>.
</p>

<p>
	أي أنّه يمكننا حساب ناتج <code>‎factorial(n)‎</code> على أنّه <code>‎n‎</code> مضروبًا بناتج <code>‎factorial(n-1)‎</code>. ويمكن أن ينخفض استدعاء <code>‎n-1‎</code> أنزل وأنزل إلى أن يصل <code>‎1‎</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_60" style="">
<span class="kwd">function</span><span class="pln"> factorial</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">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> n </span><span class="pun">*</span><span class="pln"> factorial</span><span class="pun">(</span><span class="pln">n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </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">

alert</span><span class="pun">(</span><span class="pln"> factorial</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 120</span></pre>

<p>
	القيمة الأساس للتعاود هي <code>‎1‎</code>. يمكننا أن نجعل <code>‎0‎</code> هي الأساس ولكنّ ذلك لا يهم، ليست إلا خطوة تعاود أخرى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_62" style="">
<span class="kwd">function</span><span class="pln"> factorial</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">return</span><span class="pln"> n </span><span class="pun">?</span><span class="pln"> n </span><span class="pun">*</span><span class="pln"> factorial</span><span class="pun">(</span><span class="pln">n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </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">

alert</span><span class="pun">(</span><span class="pln"> factorial</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 120</span></pre>

<h3>
	أعداد فيبوناتشي
</h3>

<p>
	<em>الأهمية: 5</em>
</p>

<p>
	<a href="https://ar.wikipedia.org/wiki/%D8%B9%D8%AF%D8%AF_%D9%81%D9%8A%D8%A8%D9%88%D9%86%D8%A7%D8%AA%D8%B4%D9%8A" rel="external nofollow">لمتتالية فيبوناتشي</a> الصيغة <code>F&lt;sub&gt;n&lt;/sub&gt; = F&lt;sub&gt;n-1&lt;/sub&gt; + F&lt;sub&gt;n-2&lt;/sub&gt;</code>. أي أنّ العدد التالي هو مجموع العددين الذين سبقاه.
</p>

<p>
	أوّل عددين هما <code>‎1‎</code>، وبعدها <code>‎‎2(1+1)‎</code> ثمّ <code>‎‎3(1+2)‎</code> ثمّ <code>‎‎5(2+3)‎</code> وهكذا: <code>‎‎1, 1, 2, 3, 5, 8, 13, 21...‎‎</code>.
</p>

<p>
	ترتبط أعداد فيبوناتشي <a href="https://ar.wikipedia.org/wiki/%D9%86%D8%B3%D8%A8%D8%A9_%D8%B0%D9%87%D8%A8%D9%8A%D8%A9" rel="external nofollow">بالنسبة الذهبية</a> وبظواهر طبيعية أخرى عديدة حولنا من كلّ مكان.
</p>

<p>
	اكتب الدالة <code>‎fib(n)‎</code> لتُعيد عدد فيبوناتش <code>‎n-th‎</code>.
</p>

<p>
	مثال لطريقة عملها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_64" style="">
<span class="kwd">function</span><span class="pln"> fib</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="com">/* شيفرتك هنا */</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">fib</span><span class="pun">(</span><span class="lit">3</span><span class="pun">));</span><span class="pln"> </span><span class="com">// 2</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">fib</span><span class="pun">(</span><span class="lit">7</span><span class="pun">));</span><span class="pln"> </span><span class="com">// 13</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">fib</span><span class="pun">(</span><span class="lit">77</span><span class="pun">));</span><span class="pln"> </span><span class="com">// 5527939700884757</span></pre>

<p>
	ملاحظة: يجب أن تعمل الدالة بسرعة. يجب ألا يأخذ استعداء <code>‎fib(77)‎</code> أكثر من جزء من الثانية.
</p>

<h4>
	الحل
</h4>

<p>
	أوّل حلّ نفكّر به هو الحلّ بالتعاود.
</p>

<p>
	أعداد فيبوناتشي تعاودية حسب تعريفها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_66" style="">
<span class="kwd">function</span><span class="pln"> fib</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">return</span><span class="pln"> n </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> n </span><span class="pun">:</span><span class="pln"> fib</span><span class="pun">(</span><span class="pln">n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> fib</span><span class="pun">(</span><span class="pln">n </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">

alert</span><span class="pun">(</span><span class="pln"> fib</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> fib</span><span class="pun">(</span><span class="lit">7</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 13</span><span class="pln">
</span><span class="com">// fib(77); // سيكون استدعاءً أبطأ من السلحفاة</span></pre>

<p>
	…ولكن لو كانت قيمة <code>‎n‎</code> كبيرة فسيكون بطيئًا جدًا. يمكن أن يعلّق الاستدعاء <code>‎fib(77)‎</code> محرّك جافاسكربت لفترة من الوقت بينما يستهلك موارد المعالج كاملةً.
</p>

<p>
	يعزو ذلك إلى أنّ الدالة تؤدّي استدعاءات فرعية كثيرة، وتُعيد تقدير (evaluate) القيم ذاتها مرارًا وتكرارًا.
</p>

<p>
	لنرى مثلًا جزءًا من حسابات <code>‎fib(5)‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_68" style="">
<span class="pun">...</span><span class="pln">
fib</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> fib</span><span class="pun">(</span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> fib</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln">
fib</span><span class="pun">(</span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> fib</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> fib</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="pun">...</span></pre>

<p>
	يمكننا أن نرى هنا بأنّ قيمة <code>‎fib(3)‎</code> مفيدة للاستدعائين <code>‎fib(5)‎</code> و<code>‎fib(4)‎</code>. لذا فستُستدعى <code>‎fib(3)‎</code> وتُقدّر قيمتها مرتين كاملتين منفصلتين عن بعضهما البعض.
</p>

<p>
	إليك شجرة التعاود كاملةً:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="37833" href="https://academy.hsoub.com/uploads/monthly_2020_04/fibonacci-recursion-tree.png.74c6aae9e1e5641f47dcd67869223c5e.png" rel=""><img alt="fibonacci-recursion-tree.png" class="ipsImage ipsImage_thumbnailed" data-fileid="37833" data-unique="6f3y6ryy9" src="https://academy.hsoub.com/uploads/monthly_2020_04/fibonacci-recursion-tree.thumb.png.686fd4c53848015def32865eeb824452.png"></a>
</p>

<p>
	نرى بوضوح كيف أنّ <code>‎fib(3)‎</code> تُقدّر مرتين اثنتين و<code>‎fib(2)‎</code> تُقدّر ثلاث مرات. إجمالي الحسابات يزداد أسرع مما تزداد قيمة <code>‎n‎</code>، ما يجعل الحسابات مهولة حين نصل <code>‎n=77‎</code>.
</p>

<p>
	يمكننا تحسين أداء الشيفرة بتذكّر القيم التي قدّرنا ناتجها قبل الآن: لو حسبنا قيمة <code>‎fib(3)‎</code> مثلًا، فيمكننا إعادة استعمالها في أيّ حسابات مستقبلية.
</p>

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

<p>
	فبدلًا من أن نبدأ بِ <code>‎n‎</code> وننطلق نحو أسفل، يمكن أن نصنع حلقة تبدأ من <code>‎1‎</code> و<code>‎2‎</code> ثمّ تسجّل ناتج ذلك على أنّه <code>‎fib(3)‎</code>، وناتج القيمتين السابقتين على أنّه <code>‎fib(4)‎</code> وهكذا دواليك إلى أن تصل إلى القيمة المطلوبة. هكذا لا نتذكّر في كلّ خطوة إلى قيمتين سابقتين فقط.
</p>

<p>
	إليك خطوات الخوارزمية الجديدة هذه بالتفصيل الممل.
</p>

<p>
	البداية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_70" style="">
<span class="com">// ‫a = fib(1)‎، ‏b = fib(2)‎، هذه القيم حسب التعريف رقم 1</span><span class="pln">
let a </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> b </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">// ‫نأخذ c = fib(3)‎ ليكون مجموعها</span><span class="pln">
let c </span><span class="pun">=</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">

</span><span class="com">/* ‫لدينا الآن fib(1)‎ و fib(2)‎ و fib(3)‎
a  b  c
1, 1, 2
*/</span></pre>

<p>
	الآن نريد معرفة <code>‎fib(4) = fib(2) + fib(3)‎</code>.
</p>

<p>
	لنحرّك ما في المتغيّرات إلى الجانب: <code>‎a,b‎</code> سيكونان <code>‎fib(2),fib(3)‎</code> و<code>‎c‎</code> سيكون مجموعهما:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_72" style="">
<span class="pln">a </span><span class="pun">=</span><span class="pln"> b</span><span class="pun">;</span><span class="pln"> </span><span class="com">// now a = fib(2)</span><span class="pln">
b </span><span class="pun">=</span><span class="pln"> c</span><span class="pun">;</span><span class="pln"> </span><span class="com">// now b = fib(3)</span><span class="pln">
c </span><span class="pun">=</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln"> </span><span class="com">// c = fib(4)</span><span class="pln">

</span><span class="com">/* الآن لدينا المتتابعة:
   a  b  c
1, 1, 2, 3
*/</span></pre>

<p>
	الخطوة التالية تعطينا عددًا آخر في السلسلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_74" style="">
<span class="pln">a </span><span class="pun">=</span><span class="pln"> b</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫الآن صار a = fib(3)‎</span><span class="pln">
b </span><span class="pun">=</span><span class="pln"> c</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫الآن صار b = fib(4)‎</span><span class="pln">
c </span><span class="pun">=</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln"> </span><span class="com">// c = fib(5)</span><span class="pln">

</span><span class="com">/* ‫الآن لدينا المتتابعة (أضفنا عددًا آخر):
      a  b  c
1, 1, 2, 3, 5
*/</span></pre>

<p>
	…وهكذا إلى أن نصل إلى القيمة المطلوبة. وهذا أسرع بكثير من التعاود وليس فيه أيّة حسابات متكرّرة.
</p>

<p>
	الشيفرة كاملةً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_76" style="">
<span class="kwd">function</span><span class="pln"> fib</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">
  let a </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
  let b </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">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</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">
    let c </span><span class="pun">=</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
    a </span><span class="pun">=</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
    b </span><span class="pun">=</span><span class="pln"> c</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"> b</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fib</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> fib</span><span class="pun">(</span><span class="lit">7</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 13</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> fib</span><span class="pun">(</span><span class="lit">77</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5527939700884757</span></pre>

<p>
	تبدأ الحلقة بالقيمة <code>‎i=3‎</code> إذ أنّ قيمتا المتتابعة الأولى والثانية مكتوبتان داخل المتغيّران <code>‎a=1‎</code> و <code>‎b=1‎</code>.
</p>

<p>
	يُدعى هذا الأسلوب <a href="https://ar.wikipedia.org/wiki/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9_%D8%AF%D9%8A%D9%86%D8%A7%D9%85%D9%8A%D9%83%D9%8A%D8%A9" rel="external nofollow">بالبرمجة الديناميكية من أسفل إلى أعلى</a>.
</p>

<h3>
	طباعة قائمة مترابطة
</h3>

<p>
	لنقل بأنّ أمامنا القائمة المترابطة هذه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_78" style="">
<span class="pln">let list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
      next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
        next</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	اكتب الدالة <code>‎printList(list)‎</code> لتطبع لنا عناصر القائمة واحدةً واحدة.
</p>

<p>
	اصنع نسختين من الحل: واحدة باستعمال الحلقات وواحدة باستعمال التعاود.
</p>

<p>
	أيّ الحلّين أفضل؟ بالتعاود أو بدون؟
</p>

<h4>
	الحل
</h4>

<p>
	<strong>نسخة الحلقات</strong>
</p>

<p>
	هذا الحلّ باستعمال الحلقات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_80" style="">
<span class="pln">let list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
      next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
        next</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> printList</span><span class="pun">(</span><span class="pln">list</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let tmp </span><span class="pun">=</span><span class="pln"> list</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">tmp</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">tmp</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
    tmp </span><span class="pun">=</span><span class="pln"> tmp</span><span class="pun">.</span><span class="pln">next</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

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

printList</span><span class="pun">(</span><span class="pln">list</span><span class="pun">);</span></pre>

<p>
	لاحظ كيف استعملنا المتغير المؤقت <code>‎tmp‎</code> للمرور على عناصر القائمة. يمكننا نظريًا استعمال مُعامل الدالة <code>‎list‎</code> بدل ذلك:
</p>

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

  </span><span class="kwd">while</span><span class="pun">(</span><span class="pln">list</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">list</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
    list </span><span class="pun">=</span><span class="pln"> list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

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

<p>
	ولكن… سنندم على ذلك لاحقًا إذ قد نحتاج إلى توسيع عمل الدالة وإجراء عملية أخرى غير هذه على القائمة، ولو بدّلنا <code>‎list‎</code> فلن نقدر على ذلك حتمًا.
</p>

<p>
	وعلى سيرة الحديث عن تسمية المتغيرات «كما ينبغي»، فهنا تُعدّ القائمةُ <code>‎list‎</code> ذاتَ القائمة، أي العنصر الأوّل من تلك القائمة، ويجب أن يبقى الاسم كما هو هكذا، مقروءًا وواضحًا.
</p>

<p>
	بينما لا يعدو دور <code>‎tmp‎</code> إلّا أداةً لمسح القائمة، تمامًا مثل <code>‎i‎</code> في حلقات <code>‎for‎</code>.
</p>

<p>
	<strong>نسخة التعاود</strong>
</p>

<p>
	مفهوم النسخة التعاودية من الدالة <code>‎printList(list)‎</code> بسيط: علينا -كي نطبع قائمةً- طباعةَ العنصر الحالي <code>‎list‎</code> وتكرار ذلك على كلّ <code>‎list.next‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_84" style="">
<span class="pln">let list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
      next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
        next</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> printList</span><span class="pun">(</span><span class="pln">list</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">list</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln"> </span><span class="com">// نطبع العنصر الحالي</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    printList</span><span class="pun">(</span><span class="pln">list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ذات الحركة لكلّ عنصر باقٍ في القائمة</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

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

printList</span><span class="pun">(</span><span class="pln">list</span><span class="pun">);</span></pre>

<p>
	أمّا الآن، فأيّ النسختين أفضل؟
</p>

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

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

<h3>
	طباعة قائمة مترابطة بالعكس
</h3>

<p>
	<em>الأهمية: 5</em>
</p>

<p>
	اطبع القائمة المترابطة من التمرين السابق، ولكن بعكس ترتيب العناصر.
</p>

<p>
	اصنع نسختين من الحل: واحدة باستعمال الحلقات وواحدة باستعمال التعاود.
</p>

<h4>
	الحل
</h4>

<p>
	<strong>نسخة التعاود</strong>
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_86" style="">
<span class="pln">let list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
      next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
        next</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> printReverseList</span><span class="pun">(</span><span class="pln">list</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">list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    printReverseList</span><span class="pun">(</span><span class="pln">list</span><span class="pun">.</span><span class="pln">next</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">list</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">

printReverseList</span><span class="pun">(</span><span class="pln">list</span><span class="pun">);</span></pre>

<p>
	<strong>نسخة الحلقات</strong>
</p>

<p>
	نسخة الحلقات هنا أكثر تعقيدًا (بقليل) عن سابقتها.
</p>

<p>
	ما من طريقة لنأخذ آخر قيمة في قائمتنا <code>‎list‎</code>، ولا يمكننا أن «نعود» فيها.
</p>

<p>
	لذا يمكننا أوّلًا المرور على العناصر بالترتيب المباشر وحِفظها في مصفوفة، بعدها طباعة ما حفظناه بالعكس:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2895_88" style="">
<span class="pln">let list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
      next</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
        next</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> printReverseList</span><span class="pun">(</span><span class="pln">list</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">
  let tmp </span><span class="pun">=</span><span class="pln"> list</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">tmp</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    arr</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">tmp</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
    tmp </span><span class="pun">=</span><span class="pln"> tmp</span><span class="pun">.</span><span class="pln">next</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="pln">let i </span><span class="pun">=</span><span class="pln"> arr</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"> i </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</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">
    alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

printReverseList</span><span class="pun">(</span><span class="pln">list</span><span class="pun">);</span></pre>

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

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/recursion" rel="external nofollow">Recursion and stack</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">870</guid><pubDate>Mon, 06 Apr 2020 18:00:00 +0000</pubDate></item><item><title>&#x635;&#x64A;&#x63A;&#x629; JSON &#x648;&#x62A;&#x648;&#x627;&#x628;&#x639;&#x647;&#x627; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/43.jpg.6b2993ce71343e1be59be7eef4945446.jpg" /></p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_7" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">

  toString</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">name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"${this.name}"</span><span class="pun">,</span><span class="pln"> age</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">age</span><span class="pun">}}`;</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="pln">user</span><span class="pun">);</span><span class="pln"> </span><span class="com">// {name: "John", age: 30}</span></pre>

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

<p>
	لحسن حظّنا فكتابة تلك الشيفرة لهذه المعضلة ليس له داعٍ، فهناك من حلّها بالفعل.
</p>

<h2>
	JSON.stringify
</h2>

<p>
	نسق <a href="http://en.wikipedia.org/wiki/JSON" rel="external nofollow">JSON</a> (صيغة كائنات جافاسكربت <strong>J</strong>ava<strong>S</strong>cript <strong>O</strong>bject <strong>N</strong>otation) هو نسق عام لتمثيل القيم والكائنات، ويوثّقه المعيار <a href="http://tools.ietf.org/html/rfc4627" rel="external nofollow">RFC 4627</a>. في بادئ الأمر كان غرض كتابته هو لاستعماله في جافاسكربت، ولكن رويدًا رويدًا بدأت اللغات الأخرى صناعة مكتبات تتعامل معه أيضًا. لهذا يسهل لنا استعمال JSON لتبادل البيانات حين يستعمل جهاز العميل جافاسكربت بينما الخادوم مكتوب بلغة روبي/PHP/جافا/أي لغة خنفشارية أخرى.
</p>

<p>
	تقدّم جافاسكربت التوابِع الآتية:
</p>

<ul>
<li>
		<code>JSON.stringify</code> لتحويل الكائنات إلى صياغة JSON.
	</li>
	<li>
		<code>JSON.parse</code> لإرجاع بيانات مصاغة بصياغة JSON إلى كائن كما كان.
	</li>
</ul>
<p>
	فمثلًا هنا نستعمل <code>JSON.stringify</code> على طالب <code>student</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_9" style="">
<span class="pln">let student </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">'John'</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">
  isAdmin</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  courses</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'html'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'css'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'js'</span><span class="pun">],</span><span class="pln">
  wife</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let json </span><span class="pun">=</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">student</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="kwd">typeof</span><span class="pln"> json</span><span class="pun">);</span><span class="pln"> </span><span class="com">// حصلنا على سلسلة نصيةّ</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">json</span><span class="pun">);</span><span class="pln">

</span><span class="com">/* ‫كائن مرمّز بِـJSON:
{
  "name": "John",
  "age": 30,
  "isAdmin": false,
  "courses": ["html", "css", "js"],
  "wife": null
}
*/</span></pre>

<p>
	يأخذ التابِع <code>JSON.stringify(student)‎</code> الكائن ويحوّله إلى سلسلة نصية. تُسمّى سلسلة <code>json</code> النصية الناتج بكائن <em>مرمّز بِـJSON (JSON-encoded)‎</em> أو <em>مُسلسل (serialized)</em> أو <em>stringified</em> أو <em>marshalled</em>. صرنا مستعدّين لإرسال الكائن عبر الوِب أو تخزينه في مخزن بيانات خام.
</p>

<p>
	لاحظ من فضلك الاختلافات المهمة بين الكائن المرمّز بِـJSON من الكائن العادي الحرفي:
</p>

<ul>
<li>
		تستعمل السلاسل النصية علامات اقتباس مزدوجة. لا مكان لعلامات الاقتباس المفردة أو الفواصل <code>`</code> في JSON. بهذا يصير <code>'John'</code> هكذا <code>"John"</code>.
	</li>
	<li>
		حتّى خاصيات الكائنات تُحاط بعلامات اقتباس مزدوجة، ولا مناص من ذلك. بهذا يصير <code>age:30</code> هكذا <code>"age":30</code>.
	</li>
</ul>
<p>
	يمكن استعمال <code>JSON.stringify</code> على الأنواع الأولية أيضًا.
</p>

<p>
	تدعم JSON أنواع البيانات الآتية:
</p>

<ul>
<li>
		<p>
			الكائنات <code>{ ... }</code>
		</p>
	</li>
	<li>
		<p>
			المصفوفات <code>[ ... ]</code>
		</p>
	</li>
	<li>
		<p>
			الأنواع الأولية:
		</p>

		<ul>
<li>
				السلاسل النصية,
			</li>
			<li>
				الأعداد,
			</li>
			<li>
				القيم المنطقية <code>true/false</code>,
			</li>
			<li>
				قيمة اللاشيء <code>null</code>.
			</li>
		</ul>
<p>
			مثال:
		</p>
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_11" style="">
<span class="com">// ‫العدد في JSON ليس إلّا عددًا</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="com">// 1</span><span class="pln">

</span><span class="com">// ‫السلسلة النصية في JSON ليست إلّا سلسلة نصيّة، بين علامات اقتباس مزودجة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="str">'test'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="com">// "test"</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">([</span><span class="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="pun">);</span><span class="pln"> </span><span class="com">// [1,2,3]</span></pre>

<p>
	مواصفة JSON هي مواصفة مستقلّة لغويًا وتحمل البيانات فقط. لذا يُهمِل <code>JSON.stringify</code> خاصيات الكائنات الخاصّة بجافاسكربت.
</p>

<p>
	نذكر منها:
</p>

<ul>
<li>
		خاصيات الدوال (التوابِع).
	</li>
	<li>
		الخاصيات الرمزية.
	</li>
	<li>
		الخاصيات التي تُخزّن <code>undefined</code>.
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_13" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ignored</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">
  </span><span class="pun">[</span><span class="typ">Symbol</span><span class="pun">(</span><span class="str">"id"</span><span class="pun">)]:</span><span class="pln"> </span><span class="lit">123</span><span class="pun">,</span><span class="pln"> </span><span class="com">// يتجاهلها</span><span class="pln">
  something</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pln"> </span><span class="com">// يتجاهلها</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫{} (كائن فارغ)</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_15" style="">
<span class="pln">let meetup </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Conference"</span><span class="pun">,</span><span class="pln">
  room</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">23</span><span class="pun">,</span><span class="pln">
    participants</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"john"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"ann"</span><span class="pun">]</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="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">meetup</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="com">/* البنية كاملة تتحوّل إلى سلسلة نصية:
{
  "title":"Conference",
  "room":{"number":23,"participants":["john","ann"]},
}
*/</span></pre>

<p>
	إليك التقييد: وجود الإشارات التعاودية (circular references) ممنوع. مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_17" style="">
<span class="pln">let room </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">23</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let meetup </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Conference"</span><span class="pun">,</span><span class="pln">
  participants</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"john"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"ann"</span><span class="pun">]</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

meetup</span><span class="pun">.</span><span class="pln">place </span><span class="pun">=</span><span class="pln"> room</span><span class="pun">;</span><span class="pln">      </span><span class="com">// ‫يُشير الاجتماع إلى الغرفة (meetup -&gt; room)</span><span class="pln">
room</span><span class="pun">.</span><span class="pln">occupiedBy </span><span class="pun">=</span><span class="pln"> meetup</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫تُشير الغرفة إلى الاجتماع (room -&gt; meetup)</span><span class="pln">

JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">meetup</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫خطأ تحاول تحويل بنية تعاوية إلى JSON</span></pre>

<p>
	هنا فشل التحويل بسبب الإشارات التعاودية: فتُشير <code>room.occupiedBy</code> إلى <code>meetup</code> و<code>meetup.place</code> إلى <code>room</code>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="33732" href="https://academy.hsoub.com/uploads/monthly_2020_02/json-meetup.png.20dbc2bbebefd40a12abf53fb6d28bd7.png" rel=""><img alt="json-meetup.png" class="ipsImage ipsImage_thumbnailed" data-fileid="33732" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/json-meetup.png.20dbc2bbebefd40a12abf53fb6d28bd7.png"></a>
</p>

<h2>
	الاستثناءات وتعديل الكائنات: آلة الاستبدال
</h2>

<p>
	إليك الصياغة الكاملة للتابِع <code>JSON.stringify</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_19" style="">
<span class="pln">let json </span><span class="pun">=</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">value</span><span class="pun">[,</span><span class="pln"> replacer</span><span class="pun">,</span><span class="pln"> space</span><span class="pun">])</span></pre>

<p>
	المعاملات:
</p>

<ul>
<li>
		<p>
			<code>value</code>: القيمة التي ستُرمّز.
		</p>
	</li>
	<li>
		<p>
			<code>replacer</code>: : مصفوفة من الخاصيات لترميزها، أو دالة ربط (mapping‏) بالشكل <code>function(key, value)‎</code>.
		</p>
	</li>
	<li>
		<p>
			<code>space</code>: عدد المسافات لاستعمالها لتنسيق السلسلة النصية.
		</p>
	</li>
</ul>
<p>
	في أغلب الوقت نستعمل <code>JSON.stringify</code> بتمرير المُعامل الأول فقط. ولكن لو أردنا تعديل عملية الاستبدال مثل تعديل الإشارات التعاودية، فيمكننا استعمال المُعامل الثاني للتابِع.
</p>

<p>
	لو مرّرنا مصفوفة فيها خاصيات، فستُرمّز تلك الخاصيات فقط. مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_21" style="">
<span class="pln">let room </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">23</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let meetup </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Conference"</span><span class="pun">,</span><span class="pln">
  participants</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">"John"</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">"Alice"</span><span class="pun">}],</span><span class="pln">
  place</span><span class="pun">:</span><span class="pln"> room </span><span class="com">// يُشير الاجتماع إلى الغرفة</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

room</span><span class="pun">.</span><span class="pln">occupiedBy </span><span class="pun">=</span><span class="pln"> meetup</span><span class="pun">;</span><span class="pln"> </span><span class="com">// room references meetup</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">meetup</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="str">'title'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'participants'</span><span class="pun">])</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="com">// {"title":"Conference","participants":[{},{}]}</span></pre>

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

<p>
	لنضمّن في تلك القائمة كلّ خاصية عدا <code>room.occupiedBy</code> إذ ستتسبّب بإشارة تعاودية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_23" style="">
<span class="pln">let room </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">23</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let meetup </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Conference"</span><span class="pun">,</span><span class="pln">
  participants</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">"John"</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">"Alice"</span><span class="pun">}],</span><span class="pln">
  place</span><span class="pun">:</span><span class="pln"> room </span><span class="com">// يُشير الاجتماع إلى الغرفة</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

room</span><span class="pun">.</span><span class="pln">occupiedBy </span><span class="pun">=</span><span class="pln"> meetup</span><span class="pun">;</span><span class="pln"> </span><span class="com">// تُشير الغرفة إلى الاجتماع</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">meetup</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="str">'title'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'participants'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'place'</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">'number'</span><span class="pun">])</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="com">/*
{
  "title":"Conference",
  "participants":[{"name":"John"},{"name":"Alice"}],
  "place":{"number":23}
}
*/</span></pre>

<p>
	الآن سَلسلنا كلّ ما في <code>occupiedBy</code>، ولكن قائمة الخاصيات صارت طويلة. لحسن حظّنا يمكننا استعمال دالة بدل المصفوفة لتكون آلة الاستبدال <code>replacer</code>. ستُستدعى الدالة لكلّ زوج <code>(key, value)</code> ويجب أن تُعيد القيمة ”المُستبدَلة“ التي ستحلّ مكان الأصلية، أو <code>undefined</code> لو أردنا إهمال الخاصية.
</p>

<p>
	في حالتنا هذه سنُعيد القيمة <code>value</code> ”كما هي“ لكل الخاصيات باستثناء <code>occupiedBy</code>. لنُهمل <code>occupiedBy</code> ستُعيد الشيفرة <code>undefined</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_25" style="">
<span class="pln">let room </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">23</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let meetup </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Conference"</span><span class="pun">,</span><span class="pln">
  participants</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">"John"</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">"Alice"</span><span class="pun">}],</span><span class="pln">
  place</span><span class="pun">:</span><span class="pln"> room </span><span class="com">// يُشير الاجتماع إلى الغرفة</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

room</span><span class="pun">.</span><span class="pln">occupiedBy </span><span class="pun">=</span><span class="pln"> meetup</span><span class="pun">;</span><span class="pln"> </span><span class="com">// تُشير الغرفة إلى الاجتماع</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">meetup</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> replacer</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">key</span><span class="pun">}:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">value</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">key </span><span class="pun">==</span><span class="pln"> </span><span class="str">'occupiedBy'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> value</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}));</span><span class="pln">

</span><span class="com">/* أزواج ‫key:value التي تدخل آلة الاستبدال:
:             [object Object]
title:        Conference
participants: [object Object],[object Object]
0:            [object Object]
name:         John
1:            [object Object]
name:         Alice
place:        [object Object]
number:       23
*/</span></pre>

<p>
	لاحِظ بأنّ الدالة <code>replacer</code> تأخذ كلّ زوج ”مفتاح/قيمة“ بما في ذلك الكائنات المتداخلة وعناصر المصفوفات، فهي تتطبّق تكراريًا. وقيمة <code>this</code> داخل <code>replacer</code> هي الكائن الذي يحتوي على الخاصية الحالية.
</p>

<p>
	الاستدعاء الأوّل خاصّ قليلًا، فهو يستلم ”كائن تغليف“: <code>{"": meetup}</code>. بعبارة أخرى فأوّل زوج <code>(key, value)</code> يكون مفتاحه فارغًا وقيمته هي الكائن الهدف كلّه. لهذا نرى السطر الأول في المثال أعلاه: <code>":[object Object]"</code>.
</p>

<p>
	الغرض هو تقديم كلّ ما أمكن من ”تسلّط“ لأداة الاستبدال، بهذا يمكنها تحليل الكائنات كاملةً واستبدالها أو إهمالها لو تطلّب الأمر.
</p>

<h2>
	التنسيق: المسافات
</h2>

<p>
	المُعامل الثالث للتابِع <code>JSON.stringify(value, replacer, space)‎</code> هو عدد المسافات التي ستُستعمل لتنسيقها تنسيقًا جميلًا (Pretty format).
</p>

<p>
	في المثال السابق، لم يكن للكائنات المُسلسلة (stringified objects) أيّة مسافات أو مسافات بادئة. لا بأس لو كنّا سنرسل الكائن عبر الشبكة، فالمُعامل <code>space</code> يُستعمل فقط لتجميل الناتج.
</p>

<p>
	هنا بعبارة <code>space = 2</code> نقول لجافاسكربت بأن تعرض الكائنات المتداخلة على عدّة أسطر، بمسافتين بادئتين داخل كل كائن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_27" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln">
  roles</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    isAdmin</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    isEditor</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">));</span><span class="pln">
</span><span class="com">/* ‫إزاحة بمسافتين:
{
  "name": "John",
  "age": 25,
  "roles": {
    "isAdmin": false,
    "isEditor": true
  }
}
*/</span><span class="pln">

</span><span class="com">/* ‫بينما JSON.stringify(user, null, 4)‎ يعطينا إزاحة أكبر:
{
    "name": "John",
    "age": 25,
    "roles": {
        "isAdmin": false,
        "isEditor": true
    }
}
*/</span></pre>

<p>
	نستعمل المُعامل <code>space</code> فقط لغرض الناتج الجميل وعمليات تسجيل المخرجات.
</p>

<h2>
	تابِع ”toJSON“ مخصّص
</h2>

<p>
	كما يوجد <code>toString</code> للتحويل إلى سلاسل نصية، يمكن للكائنات أيضًا تقديم تابِع <code>toJSON</code> للتحويل إلى JSON. تستدعي <code>JSON.stringify</code> ذاك التابِع تلقائيًا لو وجدته. مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_29" style="">
<span class="pln">let room </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">23</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let meetup </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Conference"</span><span class="pun">,</span><span class="pln">
  date</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="typ">Date</span><span class="pun">.</span><span class="pln">UTC</span><span class="pun">(</span><span class="lit">2017</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">1</span><span class="pun">)),</span><span class="pln">
  room
</span><span class="pun">};</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">meetup</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="com">/*
  {
    "title":"Conference",
    "date":"2017-01-01T00:00:00.000Z",  // (1)
    "room": {"number":23}               // (2)
  }
*/</span></pre>

<p>
	نرى هنا بأنّ <code>date</code> (في <code>(1)</code>) صار سلسلة نصية. هذا لأنّ التواريخ كلّها توفّر تنفيذًا للتابِع <code>toJSON</code> مضمّنًا فيها، وهو يُعيد سلاسل نصية بهذا التنسيق.
</p>

<p>
	لنُضيف الآن تابِع <code>toJSON</code> مخصّص للكائن <code>room</code> (في <code>(2)</code>):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_31" style="">
<span class="pln">let room </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">23</span><span class="pun">,</span><span class="pln">
  toJSON</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">number</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let meetup </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Conference"</span><span class="pun">,</span><span class="pln">
  room
</span><span class="pun">};</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">room</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 23</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">meetup</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="com">/*
  {
    "title":"Conference",
    "room": 23
  }
*/</span></pre>

<p>
	كما نرى، استُعمِل التابِع <code>toJSON</code> مرتين، مرة حين استدعاه <code>JSON.stringify(room)‎</code> مباشرةً، ومرة حين كانت الخاصية <code>room</code> داخل كائن مرمّز آخر.
</p>

<h2>
	التابع JSON.parse
</h2>

<p>
	لنفكّ ترميز سلسلة JSON نصية، سنحتاج تابِعًا آخر بالاسم <a href="https://wiki.hsoub.com/JavaScript/JSON/parse" rel="external">JSON.parse</a>. صياغته هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_35" style="">
<span class="pln">let value </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">str</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="pln">reviver</span><span class="pun">]);</span></pre>

<p>
	المعاملات:
</p>

<ul>
<li>
		<p>
			<code>str</code>: سلسلة JSON النصية التي سيُحلّلها.
		</p>
	</li>
	<li>
		<p>
			<code>reviver</code>: دالة اختيارية <code>function(key,value)‎</code> تُستدعى لكلّ زوج <code>(key, value)</code> ويمكن لها تعديل القيمة.
		</p>
	</li>
</ul>
<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_37" style="">
<span class="com">// ‫مصفوفة مُسلسلة (stringified array)</span><span class="pln">
let numbers </span><span class="pun">=</span><span class="pln"> </span><span class="str">"[0, 1, 2, 3]"</span><span class="pun">;</span><span class="pln">

numbers </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">numbers</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> numbers</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"> </span><span class="com">// 1</span></pre>

<p>
	أو حين استعمالها للكائنات المتداخلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_39" style="">
<span class="pln">let userData </span><span class="pun">=</span><span class="pln"> </span><span class="str">'{ "name": "John", "age": 35, "isAdmin": false, "friends": [0,1,2,3] }'</span><span class="pun">;</span><span class="pln">

let user </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">userData</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">friends</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"> </span><span class="com">// 1</span></pre>

<p>
	يمكن أن يكون كائن JSON بالتعقيد اللازم مهمًا كان. يمكن أن تحتوي الكائنات والمصفوفات كائناتَ ومصفوفات أخرى، ولكنّ لزامٌ عليها أن تلتزم بنفس نسق JSON.
</p>

<p>
	إليك بعض المشاكل الشائعة حين كتابة JSON يدويًا (أحيانًا نفعل ذلك لأغراض تنقيح الشيفرات):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_41" style="">
<span class="pln">let json </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">"John"</span><span class="pun">,</span><span class="pln">                     </span><span class="com">// خطأ: اسم خاصية بدون علامات اقتباس</span><span class="pln">
  </span><span class="str">"surname"</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Smith'</span><span class="pun">,</span><span class="pln">               </span><span class="com">// خطأ: علامات اقتباس مُفردة في القيمة (يجب أن تكون مزودجة)‏</span><span class="pln">
  </span><span class="str">'isAdmin'</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">                  </span><span class="com">// خطأ: علامات اقتباس مُفردة في المفتاح (يجب أن تكون مزدوجة)‏</span><span class="pln">
  </span><span class="str">"birthday"</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">2000</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="com">// ‫خطأ: استعمال "new" ممنوع، فقط وفقط قيم</span><span class="pln">
  </span><span class="str">"friends"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="lit">0</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">3</span><span class="pun">]</span><span class="pln">              </span><span class="com">// هنا لا بأس</span><span class="pln">
</span><span class="pun">}`;</span></pre>

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

<p>
	هناك نسق آخر بالاسم <a href="http://json5.org/" rel="external nofollow">JSON5</a> ويُتيح لنا عدم إحاطة المفاتيح بعلامات اقتباس، وكتابة التعليقات وغيرها. إلّا أنّها مكتبة مستقلة وليست في مواصفة لغة جافاسكربت. لم يصنع المطوّرون كائنات JSON العادية لتكون بهذه الصرامة لأنّهم كسالى، بل لنُعوّل على شيفرات خوارزميات التحليل، إضافة إلى عملها بسرعة فائقة.
</p>

<h2>
	استعمال آلة الإحياء
</h2>

<p>
	تخيّل أنّنا استلمنا كائن <code>meetup</code> مُسلسل من الخادوم، وهذا شكله:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_43" style="">
<span class="com">// title: (meetup title), date: (meetup date)</span><span class="pln">
let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'</span><span class="pun">;</span></pre>

<p>
	…نريد الآن <em>فكّ ترميزه</em>، أي إعادته إلى كائن جافاسكربت عادي. يكون ذلك باستدعاء <code>JSON.parse</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_45" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'</span><span class="pun">;</span><span class="pln">

let meetup </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">str</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> meetup</span><span class="pun">.</span><span class="pln">date</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// خطأ‫!</span></pre>

<p>
	لحظة… خطأ؟!
</p>

<p>
	قيمة الخاصية <code>meetup.date</code> هي سلسلة نصية وليست كائن تاريخ <code>Date</code>. كيف سيعرف <code>JSON.parse</code> بأنّ عليه تعديل تلك السلسلة النصية لتصير <code>Date</code>؟
</p>

<p>
	لنمرّر الآن إلى <code>JSON.parse</code> دالة ”آلة الإحياء“ في المُعامل الثاني، وستُحيي كلّ القيم ”كما هي“، عدا <code>date</code> ستعدّلها لتكون تاريخًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_47" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'</span><span class="pun">;</span><span class="pln">

let meetup </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">str</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">key </span><span class="pun">==</span><span class="pln"> </span><span class="str">'date'</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">Date</span><span class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> value</span><span class="pun">;</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> meetup</span><span class="pun">.</span><span class="pln">date</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫الآن صار يعمل!</span></pre>

<p>
	وأجل، تعمل الشيفرة للكائنات المتداخلة أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_49" style="">
<span class="pln">let schedule </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`{</span><span class="pln">
  </span><span class="str">"meetups"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="str">"title"</span><span class="pun">:</span><span class="str">"Conference"</span><span class="pun">,</span><span class="str">"date"</span><span class="pun">:</span><span class="str">"2017-11-30T12:00:00.000Z"</span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="str">"title"</span><span class="pun">:</span><span class="str">"Birthday"</span><span class="pun">,</span><span class="str">"date"</span><span class="pun">:</span><span class="str">"2017-04-18T12:00:00.000Z"</span><span class="pun">}</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}`;</span><span class="pln">

schedule </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">schedule</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">key </span><span class="pun">==</span><span class="pln"> </span><span class="str">'date'</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">Date</span><span class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> value</span><span class="pun">;</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> schedule</span><span class="pun">.</span><span class="pln">meetups</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">date</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫يعمل!</span></pre>

<h2>
	ملخص
</h2>

<ul>
<li>
		تنسيق JSON هو تنسيق بيانات يستقلّ بمعياره ومكتباته في غالبية لغات البرمجة.
	</li>
	<li>
		يدعم JSON الكائنات العادية والمصفوفات والسلاسل النصية والأعداد والقيم المنطقية و<code>null</code>.
	</li>
	<li>
		تقدّم جافاسكربت التوابِع <a href="https://wiki.hsoub.com/JavaScript/JSON/stringify" rel="external">JSON.stringify</a> لسَلسلة الكائنات إلى JSON، و<a href="https://wiki.hsoub.com/JavaScript/JSON/parse" rel="external">JSON.parse</a> للقراءة من JSON.
	</li>
	<li>
		يدعم كلا التابِعين دوال تعديل لتكون القراءة والكتابة ”ذكيّة“.
	</li>
	<li>
		لو كان في الكائن تابِع <code>toJSON</code>، فسيستدعيه <code>JSON.stringify</code>.
	</li>
</ul>
<h2>
	تمارين
</h2>

<h3>
	تحويل الكائن إلى JSON وتحويله كما كان
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	حوّل الكائن <code>user</code> إلى JSON واقرأه ثانيةً ليكون متغيرًا آخرًا.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_51" style="">
<span class="pln">let user </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">"John Smith"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">35</span><span class="pln">
</span><span class="pun">};</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_53" style="">
<span class="pln">let user </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">"John Smith"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">35</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let user2 </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">JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">user</span><span class="pun">));</span></pre>
</div>

<h2>
	استثناء الإشارات السابقة
</h2>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

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

<p>
	اكتب دالة <code>replacer</code> تُسلسل كل شيء ولكن تُزيل الخاصيات التي تُشير إلى <code>meetup</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_55" style="">
<span class="pln">let room </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">23</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let meetup </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Conference"</span><span class="pun">,</span><span class="pln">
  occupiedBy</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">"John"</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">"Alice"</span><span class="pun">}],</span><span class="pln">
  place</span><span class="pun">:</span><span class="pln"> room
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// إشارات تعاودية</span><span class="pln">
room</span><span class="pun">.</span><span class="pln">occupiedBy </span><span class="pun">=</span><span class="pln"> meetup</span><span class="pun">;</span><span class="pln">
meetup</span><span class="pun">.</span><span class="pln">self </span><span class="pun">=</span><span class="pln"> meetup</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">meetup</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> replacer</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">/* شيفرتك هنا*/</span><span class="pln">
</span><span class="pun">}));</span><span class="pln">

</span><span class="com">/* ‫هكذا النتيجة المطلوبة:
{
  "title":"Conference",
  "occupiedBy":[{"name":"John"},{"name":"Alice"}],
  "place":{"number":23}
}
*/</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4138_57" style="">
<span class="pln">let room </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">23</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let meetup </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Conference"</span><span class="pun">,</span><span class="pln">
  occupiedBy</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">"John"</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">"Alice"</span><span class="pun">}],</span><span class="pln">
  place</span><span class="pun">:</span><span class="pln"> room
</span><span class="pun">};</span><span class="pln">

room</span><span class="pun">.</span><span class="pln">occupiedBy </span><span class="pun">=</span><span class="pln"> meetup</span><span class="pun">;</span><span class="pln">
meetup</span><span class="pun">.</span><span class="pln">self </span><span class="pun">=</span><span class="pln"> meetup</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">meetup</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> replacer</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">key </span><span class="pun">!=</span><span class="pln"> </span><span class="str">""</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> value </span><span class="pun">==</span><span class="pln"> meetup</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> value</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}));</span><span class="pln">

</span><span class="com">/* 
{
  "title":"Conference",
  "occupiedBy":[{"name":"John"},{"name":"Alice"}],
  "place":{"number":23}
}
*/</span></pre>

	<p>
		علينا هنا (أيضًا) فحص <code>key==""‎</code> لنستثني أوّل نداء إذ لا مشكلة بأن تكون القيمة <code>value</code> هي <code>meetup</code>.
	</p>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/json" rel="external nofollow">JSON methods, toJSON</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
<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-r826/" rel="">توابع الأنواع الأولية</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%86%D9%88%D8%B9-date-%D8%AA%D9%85%D8%AB%D9%8A%D9%84-%D8%A7%D9%84%D8%AA%D8%A7%D8%B1%D9%8A%D8%AE-%D9%88%D8%A7%D9%84%D9%88%D9%82%D8%AA-r825/" rel="">النوع Date: تمثيل التاريخ والوقت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">826</guid><pubDate>Sun, 23 Feb 2020 11:45:15 +0000</pubDate></item><item><title>&#x627;&#x644;&#x646;&#x648;&#x639; Date: &#x62A;&#x645;&#x62B;&#x64A;&#x644; &#x627;&#x644;&#x62A;&#x627;&#x631;&#x64A;&#x62E; &#x648;&#x627;&#x644;&#x648;&#x642;&#x62A;  &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%86%D9%88%D8%B9-date-%D8%AA%D9%85%D8%AB%D9%8A%D9%84-%D8%A7%D9%84%D8%AA%D8%A7%D8%B1%D9%8A%D8%AE-%D9%88%D8%A7%D9%84%D9%88%D9%82%D8%AA-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r825/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/42.jpg.161f8ffac31d673bbfaa2ffa40bbc9c5.jpg" /></p>

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

<h2>
	الإنشاء
</h2>

<p>
	استدعِ <code>new Date()‎</code> بتمرير واحدًا من الوُسطاء الآتية فتصنع كائن <code>Date</code> جديد:
</p>

<p>
	<strong><code>الدالة new Date()‎</code> </strong>
</p>

<p>
	تنشئ هذه الدالة بلا وُسطاء كائن <code>Date</code> بالتاريخ والوقت الحاليين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_8" style="">
<span class="pln">    let now </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">
    alert</span><span class="pun">(</span><span class="pln"> now </span><span class="pun">);</span><span class="pln"> </span><span class="com">// نعرض التاريخ والوقت الحاليين</span></pre>

<p>
	إليك كيفية إنشاء كائن <code>Date</code>: <em><code>new Date(milliseconds)‎</code></em> يُنشئ كائن <code>Date</code> إذ تساوي قيمته عدد المليثوان الممرّرة (المليثانية هي 1/1000 من الثاني) حسابًا من بعد الأول من يناير عام ١٩٧٠ بتوقيت UTC+0.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_10" style="">
<span class="pln">    </span><span class="com">// UTC+0</span><span class="pln">
    </span><span class="com">// 01.01.1970 نعني بـ 0 التاريخ</span><span class="pln">
    let </span><span class="typ">Jan01_1970</span><span class="pln"> </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">0</span><span class="pun">);</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Jan01_1970</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

    </span><span class="com">// نضيف الآن 24 ساعة لنحصل على  02.01.1970 </span><span class="pln">
    let </span><span class="typ">Jan02_1970</span><span class="pln"> </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">24</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">3600</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">
    alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Jan02_1970</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	يُسمّى العدد الصحيح الذي يمثّل عدد المليثوان التي مرّت من بداية عام 1970 <em>بالختم الزمني</em> (بصمة وقت). وهو يمثّل التاريخ بنحوٍ عددي خفيف (lightweight). يمكننا إنشاء التواريخ من الأختام الزمنية باستعمال <code>new Date(timestamp)‎</code> وتحويل كائن التاريخ <code>Date</code> الموجود إلى ختم زمني باستعمال التابِع <code>date.getTime()‎</code> (طالع أسفله).
</p>

<p>
	والتواريخ قبل الأول من يناير 1970 أختامها سالبة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_12" style="">
<span class="pln">    </span><span class="com">// ‫31 ديسمبر 1969</span><span class="pln">
    let </span><span class="typ">Dec31_1969</span><span class="pln"> </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">24</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">3600</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">
    alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Dec31_1969</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	<em><code>new Date(datestring)‎</code></em> لو كان هناك وسيط واحد وكان سلسلة نصيّة، فسيحلّله المحرّك تلقائيًا. الخوازرمية هنا هي ذات التي يستعملها <code>Date.parse</code>. لا تقلق، سنتكلم عنه لاحقًا.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_14" style="">
<span class="pln">    let date </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="str">"2017-01-26"</span><span class="pun">);</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">date</span><span class="pun">);</span></pre>

<p>
	نجد في هذا المثال أن الوقت غير محدد لذا يكون بتوقيت GMT منتصف الليل، ويحدد وفقًا للمنطقة الزمنية التي تنفذ الشيفرة ضمنها، فالنتيجة يمكن أن تكون Thu Jan 26 2017 11:00:00 للبلدان ذات المنطقة الزمنية GMT+1100 أو يمكن أن تكون Wed Jan 25 2017 16:00:00 للبلدان الواقعة في المنطقة الزمنية GMT-0800.
</p>

<p>
	<em><code>new Date(year, month, date, hours, minutes, seconds, ms)‎</code></em> يُنشئ تاريخًا بالمكوّنات الممرّرة حسب المنطقة الزمنية المحلية. أوّل وسيطين إلزاميين أما البقية اختيارية.
</p>

<p>
	يجب أن يكون العام <code>year</code> بأربع خانات: <code>2013</code> صح، <code>98</code> خطأ. يبدأ الشهر <code>month</code> بالرقم <code>0</code> (يناير) وينتهي بالعدد <code>11</code> (ديسمبر). مُعامل التاريخ <code>date</code> هو رقم اليوم من الشهر. لو لم يكن موجودًا فسيعدّه الكائن <code>1</code>. لو لم تكن مُعاملات الساعة والدقيقة والثانية والمليثانية <code>hours/minutes/seconds/ms</code> موجودة، فسيعدّها الكائن <code>0</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_17" style="">
<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">2011</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">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</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">// 1 Jan 2011, 00:00:00</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">2011</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">1</span><span class="pun">);</span><span class="pln"> </span><span class="com">// نفس تلك. الساعات والدقائق وغيرها 0 مبدئيًا</span></pre>

<p>
	أدنى دقّة للتاريخ هي مليثانية واحدة (واحد من ألف من الثانية):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_22" style="">
<span class="pln">    let date </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">2011</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">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">567</span><span class="pun">);</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> date </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1.01.2011, 02:03:04.567</span></pre>

<h2>
	الوصول إلى مكوّنات التاريخ
</h2>

<p>
	إليك التوابِع التي تتيح لك الوصول إلى العام والشهر وغيرها داخل كائن <code>Date</code>:
</p>

<ul>
<li>
		<p>
			<a href="https://wiki.hsoub.com/JavaScript/Date/getFullYear" rel="external">getFullYear()‎</a>: يجلب العام (٤ خانات)
		</p>
	</li>
	<li>
		<p>
			<a href="https://wiki.hsoub.com/JavaScript/Date/getMonth" rel="external">getMonth()‎</a>: يجلب الشهر، <strong>من 0 إلى 11</strong>.
		</p>
	</li>
	<li>
		<p>
			<a href="https://wiki.hsoub.com/JavaScript/Date/getDate" rel="external">getDate()‎</a>: يجلب رقم اليوم من الشهر، من 1 إلى 31. قد يبدو الاسم غريبًا قليلًا لك.
		</p>
	</li>
	<li>
		<p>
			التوابع <a href="https://wiki.hsoub.com/JavaScript/Date/getHours" rel="external">getHours()‎</a> و<a href="https://wiki.hsoub.com/JavaScript/Date/getMinutes" rel="external">getMinutes()‎</a> و<a href="https://wiki.hsoub.com/JavaScript/Date/getSeconds" rel="external">getSeconds()‎</a> و<a href="https://wiki.hsoub.com/JavaScript/Date/getMilliseconds" rel="external">getMilliseconds()‎</a>: تجلب مكوّنات الوقت حسب كل تابِع. (الساعة/الدقيقة/الثانية/المليثانية)
		</p>
	</li>
</ul>
<p>
	<strong>إياك بـ <code>getYear()‎</code> بل <code>getFullYear()‎</code></strong> تقدّم الكثير من محرّكات جافاسكربت التابِع غير القياسي <code>getYear()‎</code>. هذا التابِع أصبح بائدًا، فهو يُعيد العام بخانتين أحيانًا. من فضلك لا تستعمله أبدًا، بل <code>getFullYear()‎</code> لتجلب العام.
</p>

<p>
	كما يمكن أيضًا جلب رقم اليوم من الشهر:
</p>

<p>
	<strong><em>التابع <a href="https://wiki.hsoub.com/JavaScript/Date/getDay" rel="external">getDay()‎</a></em></strong>
</p>

<p>
	يجلب رقم اليوم من الأسبوع، بدءًا بِـ <code>0</code> (الأحد) وحتى <code>6</code> (السبت). أوّل يوم هو الأحد دومًا. صحيح أنّ في بعض الدول هذا غير صحيح، لكن لا يمكن تغيير القيمة إطلاقًا.
</p>

<p>
	<strong>تُعيد كلّ التوابِع أعلاه المكوّنات حسب المنطقة الزمنية المحلية.</strong>
</p>

<p>
	توجد أيضًا مثيلاتها بنظام UTC حيث تُعيد اليوم والشهر والعام وغيرها في المنطقة الزمنية UTF+0:‏ <a href="https://wiki.hsoub.com/JavaScript/Date/getUTCFullYear" rel="external">getUTCFullYear()‎</a> و<a href="https://wiki.hsoub.com/JavaScript/Date/getUTCMonth" rel="external">getUTCMonth()‎</a> و<a href="https://wiki.hsoub.com/JavaScript/Date/getUTCDay" rel="external">getUTCDay()‎</a>. ضع كلمة <code>"UTC"</code> بعد <code>"get"</code> وستجد المثيل المناسب.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_24" style="">
<span class="com">// التاريخ الحالي</span><span class="pln">
let date </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="com">// الساعة حسب المنطقة الزمنية التي أنت فيها</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getHours</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

</span><span class="com">// ‫الساعة حسب المنطقة الزمنية بتوقيت UTC+0 (أي توقيت لندن بدون التوقيت الصيفي)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getUTCHours</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	هناك (إضافةً إلى هذه التوابِع) تابِعان آخران مختلفان قليلًا ليس لهما نُسخ بتوقيت UTC:
</p>

<p>
	<strong><em>التابع <a href="https://wiki.hsoub.com/JavaScript/Date/getTime" rel="external">getTime()‎</a></em></strong>
</p>

<p>
	يُعيد ختم التاريخ الزمني، أي عدد المليثوان التي مرّت منذ الأول من يناير عام 1970 بتوقيت UTC+0.
</p>

<p>
	<strong><em>التابع <a href="https://wiki.hsoub.com/JavaScript/Date/getTimezoneOffset" rel="external">getTimezoneOffset()‎</a></em></strong>
</p>

<p>
	يُعيد الفرق بين المنطقة الزمنية الحالية وتوقيت UTC (بالدقيقة):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_26" style="">
<span class="pln">    </span><span class="com">// ‫لو كانت منطقتك الزمنية UTC-1، فالناتج 60</span><span class="pln">
    </span><span class="com">// لو كانت منطقتك الزمنية ‫UTC+3، فالناتج ‎-180</span><span class="pln">
    alert</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">getTimezoneOffset</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span></pre>

<h2>
	ضبط مكوّنات التاريخ
</h2>

<p>
	تتيح لك التوابِع الآتية ضبط مكوّنات التاريخ والوقت:
</p>

<ul>
<li>
		العام: <a href="https://wiki.hsoub.com/JavaScript/Date/setFullYear" rel="external"><code>setFullYear(year, [month], [date])‎</code></a>
	</li>
	<li>
		الشهر: <a href="https://wiki.hsoub.com/JavaScript/Date/setMonth" rel="external"><code>setMonth(month, [date])‎</code></a>
	</li>
	<li>
		التاريخ: <a href="https://wiki.hsoub.com/JavaScript/Date/setDate" rel="external"><code>setDate(date)‎</code></a>
	</li>
	<li>
		الساعة: <a href="https://wiki.hsoub.com/JavaScript/Date/setHours" rel="external"><code>setHours(hour, [min], [sec], [ms])‎</code></a>
	</li>
	<li>
		الدقيقة: <a href="https://wiki.hsoub.com/JavaScript/Date/setMinutes" rel="external"><code>setMinutes(min, [sec], [ms])‎</code></a>
	</li>
	<li>
		الثانية: <a href="https://wiki.hsoub.com/JavaScript/Date/setSeconds" rel="external"><code>setSeconds(sec, [ms])‎</code></a>
	</li>
	<li>
		المليثانية: <a href="https://wiki.hsoub.com/JavaScript/Date/setMilliseconds" rel="external"><code>setMilliseconds(ms)‎</code></a>
	</li>
	<li>
		الوقت بالمليثانية: <a href="https://wiki.hsoub.com/JavaScript/Date/setTime" rel="external"><code>setTime(milliseconds)‎</code></a> (تضبط التاريخ كلّه حسب عدد المليثوان منذ 01.01.1970 UTC)
	</li>
</ul>
<p>
	لدى كلّ تابع منها نسخة بتوقيت UTC (عدا <code>setTime()‎</code>). مثال: <code>setUTCHours()‎</code>.
</p>

<p>
	كما رأيت فيمكن لبعض التوابِع ضبط عدّة مكوّنات في آن واحد مثل <code>setHours</code>. المكوّنات التي لا تُمرّر لا تُعدّل.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_28" style="">
<span class="pln">let today </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">

today</span><span class="pun">.</span><span class="pln">setHours</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">today</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ما زال اليوم نفسه، ولكن الساعة تغيّرت إلى 0</span><span class="pln">

today</span><span class="pun">.</span><span class="pln">setHours</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">today</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ما زال اليوم نفسه، ولكنّا عند 00:00:00 تمامًا.</span></pre>

<h2>
	التصحيح التلقائي
</h2>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_30" style="">
<span class="pln">let date </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">2013</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">32</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫الثاني والثلاثين من يناير 2013؟!</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">date</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫...آه، تقصد الأول من فبراير 2013!</span></pre>

<p>
	تترتّب المكوّنات اللامنطقية تلقائيًا. فمثلًا لو أضفت على التاريخ ”28 فبراير 2016“ يومين اثنين، فيمكن أن يكون ”الثاني من مارس“ أو ”الأول من مارس“ لو كانت السنة كبيسة. بدل أن نفكّر بهذا الحساب، نُضيف يومين ونترك الباقي على كائن <code>Date</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_32" style="">
<span class="pln">let date </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">2016</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">28</span><span class="pun">);</span><span class="pln">
date</span><span class="pun">.</span><span class="pln">setDate</span><span class="pun">(</span><span class="pln">date</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> date </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫1 مارس 2016</span></pre>

<p>
	غالبًا ما تُستعمل هذه الميزة لنجلب التاريخ بعد فترة محدّدة من الزمن. فلنقل مثلًا نريد تاريخ ”70 ثانية من الآن“:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_34" style="">
<span class="pln">let date </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">
date</span><span class="pun">.</span><span class="pln">setSeconds</span><span class="pun">(</span><span class="pln">date</span><span class="pun">.</span><span class="pln">getSeconds</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">70</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> date </span><span class="pun">);</span><span class="pln"> </span><span class="com">// يعرض التاريخ الصحيح</span></pre>

<p>
	يمكننا أيضًا ضبط القيمة لتكون صفرًا أو حتّى بالسالب. مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_36" style="">
<span class="pln">let date </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">2016</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="pun">);</span><span class="pln"> </span><span class="com">// ‫2 يناير 2016</span><span class="pln">

date</span><span class="pun">.</span><span class="pln">setDate</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln"> </span><span class="com">// نضبط التاريخ على أول يوم من الشهر</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> date </span><span class="pun">);</span><span class="pln">

date</span><span class="pun">.</span><span class="pln">setDate</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln"> </span><span class="com">// أقل يوم ممكن هو 1، إذًا فيعدّ الكائن أنّ 0 هو آخر يوم من الشهر الماضي</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> date </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫31 ديسمبر 2015</span></pre>

<h2>
	تحويل التاريخ إلى عدد، والفرق بين تاريخين
</h2>

<p>
	حين يتحوّل كائن <code>Date</code> إلى عدد يصير ختمًا زمنيًا مطابقًا لختم <code>date.getTime()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_38" style="">
<span class="pln">let date </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">
alert</span><span class="pun">(+</span><span class="pln">date</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫عدد المليثوان، نفس ناتج date.getTime()‎</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_40" style="">
<span class="pln">let start </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="com">// نبدأ قياس الوقت</span><span class="pln">

</span><span class="com">// إلى العمل</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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">100000</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">
  let doSomething </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">*</span><span class="pln"> i </span><span class="pun">*</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let end </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="com">// ننتهي من قياس الوقت</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`</span><span class="typ">The</span><span class="pln"> loop took $</span><span class="pun">{</span><span class="pln">end </span><span class="pun">-</span><span class="pln"> start</span><span class="pun">}</span><span class="pln"> ms</span><span class="pun">`</span><span class="pln"> </span><span class="pun">);</span></pre>

<h2>
	التاريخ الآن
</h2>

<p>
	لو أردنا قياس الوقت فقط فلا نحتاج كائن <code>Date</code>، بل هناك تابِعًا خاصًا باسم <code>Date.now()‎</code> يُعيد لنا الختم الزمني الحالي.
</p>

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

<p>
	ولهذا قد يكون الأفضل كتابة الشيفرة أدناه بدل تلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_42" style="">
<span class="pln">let start </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ‫تبدأ المليثوان من تاريخ 1 يناير 1970</span><span class="pln">

</span><span class="com">// إلى العمل</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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">100000</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">
  let doSomething </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">*</span><span class="pln"> i </span><span class="pun">*</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">*!*</span><span class="pln">
let end </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">();</span><span class="pln"> </span><span class="com">// انتهينا</span><span class="pln">
</span><span class="pun">*/!*</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`</span><span class="typ">The</span><span class="pln"> loop took $</span><span class="pun">{</span><span class="pln">end </span><span class="pun">-</span><span class="pln"> start</span><span class="pun">}</span><span class="pln"> ms</span><span class="pun">`</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// نطرح الأعداد لا التواريخ</span></pre>

<h2>
	قياس الأداء
</h2>

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

<p>
	فلنقيس مثلًا دالتين اثنتين تحسبان الفرق بين تاريخين: أيهما أسرع؟ نُطلق على قياسات الأداء هذه… قياسات أداء ”Benchmark“.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_44" style="">
<span class="com">// ‫أمامنا date1 وdate2، أيّ دالة ستُعيد الفرق بينهما (بالمليثانية) أسرع من الأخرى؟‫ هذه...</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> diffSubtract</span><span class="pun">(</span><span class="pln">date1</span><span class="pun">,</span><span class="pln"> date2</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"> date2 </span><span class="pun">-</span><span class="pln"> date1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// ‫أم هذه...</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> diffGetTime</span><span class="pun">(</span><span class="pln">date1</span><span class="pun">,</span><span class="pln"> date2</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"> date2</span><span class="pun">.</span><span class="pln">getTime</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> date1</span><span class="pun">.</span><span class="pln">getTime</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وظيفة الدالتين متطابقة تمامًا، إلّا أن الثانية تستعمل التابِع <code>date.getTime()‎</code> الصريح لتجلب التاريخ بالمليثانية، بينما الأخرى تعتمد على تحويل التاريخ إلى عدد. الناتج متطابق دومًا.
</p>

<p>
	إذًا بهذه المعطيات، أيّ الدالتين أسرع؟
</p>

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

<p>
	هيًا نقيس الأداء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_46" style="">
<span class="kwd">function</span><span class="pln"> diffSubtract</span><span class="pun">(</span><span class="pln">date1</span><span class="pun">,</span><span class="pln"> date2</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"> date2 </span><span class="pun">-</span><span class="pln"> date1</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"> diffGetTime</span><span class="pun">(</span><span class="pln">date1</span><span class="pun">,</span><span class="pln"> date2</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"> date2</span><span class="pun">.</span><span class="pln">getTime</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> date1</span><span class="pun">.</span><span class="pln">getTime</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"> bench</span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let date1 </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">0</span><span class="pun">);</span><span class="pln">
  let date2 </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">

  let start </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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">100000</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> f</span><span class="pun">(</span><span class="pln">date1</span><span class="pun">,</span><span class="pln"> date2</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> start</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'Time of diffSubtract: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> bench</span><span class="pun">(</span><span class="pln">diffSubtract</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'ms'</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'Time of diffGetTime: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> bench</span><span class="pun">(</span><span class="pln">diffGetTime</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'ms'</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	عجبًا! استعمال التابِع <code>getTime()‎</code> أسرع بكثير! يعزو ذلك بسبب انعدام وجود تحويل للنوع (type conversion)، وهذا يسهّل على المحرّكات تحسين الأداء.
</p>

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

<p>
	<strong>إن أردنا التعويل على قياس الأداء، علينا إعادة تشغيل كل قياسات الأداء الموجودة أكثر من مرّة.</strong> هكذا مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_48" style="">
<span class="kwd">function</span><span class="pln"> diffSubtract</span><span class="pun">(</span><span class="pln">date1</span><span class="pun">,</span><span class="pln"> date2</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"> date2 </span><span class="pun">-</span><span class="pln"> date1</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"> diffGetTime</span><span class="pun">(</span><span class="pln">date1</span><span class="pun">,</span><span class="pln"> date2</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"> date2</span><span class="pun">.</span><span class="pln">getTime</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> date1</span><span class="pun">.</span><span class="pln">getTime</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"> bench</span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let date1 </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">0</span><span class="pun">);</span><span class="pln">
  let date2 </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">

  let start </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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">100000</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> f</span><span class="pun">(</span><span class="pln">date1</span><span class="pun">,</span><span class="pln"> date2</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> start</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let time1 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
let time2 </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">// ‫نشغّل bench(upperSlice)‎ وbench(upperLoop)‎ عشر مرات مرّة بمرّة</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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">
  time1 </span><span class="pun">+=</span><span class="pln"> bench</span><span class="pun">(</span><span class="pln">diffSubtract</span><span class="pun">);</span><span class="pln">
  time2 </span><span class="pun">+=</span><span class="pln"> bench</span><span class="pun">(</span><span class="pln">diffGetTime</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'Total time for diffSubtract: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> time1 </span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'Total time for diffGetTime: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> time2 </span><span class="pun">);</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_50" style="">
<span class="com">// أضفناه لـ”تحمية“ المحرّك قبل الحلقة الأساس</span><span class="pln">
bench</span><span class="pun">(</span><span class="pln">diffSubtract</span><span class="pun">);</span><span class="pln">
bench</span><span class="pun">(</span><span class="pln">diffGetTime</span><span class="pun">);</span><span class="pln">

</span><span class="com">// الآن نقيس</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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">
  time1 </span><span class="pun">+=</span><span class="pln"> bench</span><span class="pun">(</span><span class="pln">diffSubtract</span><span class="pun">);</span><span class="pln">
  time2 </span><span class="pun">+=</span><span class="pln"> bench</span><span class="pun">(</span><span class="pln">diffGetTime</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<strong>الزم الحذر متى ما أجريت قياسات أداء على المستوى الذرّي</strong>.
</p>

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

<p>
	يمكنك أن تقرأ بعض المقالات الرائعة حول V8 هنا <a href="mrale.ph" rel="">http://mrale.ph</a>.
</p>

<h2>
	تحليل سلسلة نصية باستعمال Date.parse
</h2>

<p>
	يمكن أن يقرأ التابِع <a href="https://wiki.hsoub.com/JavaScript/Date/parse" rel="external">Date.parse(str)</a><code>‎</code> تاريخًا من سلسلة نصية. يجب أن يكون تنسيق تلك السلسلة هكذا: <code>YYYY-MM-DDTHH:mm:ss.sssZ</code>، إذ تعني:
</p>

<ul>
<li>
		<code>YYYY-MM-DD</code> -- التاريخ: اليوم-الشهر-العام.
	</li>
	<li>
		يُستعمل المحرف <code>"T"</code> فاصِلًا.
	</li>
	<li>
		<code>HH:mm:ss.sss</code> -- الوقت: المليثانية والثانية والدقيقة والساعة.
	</li>
	<li>
		يمثّل الجزء الاختياري <code>'Z'</code> المنطقة الزمنية حسب التنسيق <code>+-hh:mm</code>. لو وضعت <code>Z</code> فقط فذلك يعني UTC+0.
	</li>
</ul>
<p>
	يمكنك أيضًا استعمال تنسيقات أقصر مثل <code>YYYY-MM-DD</code> أو <code>YYYY-MM</code> أو حتّى <code>YYYY</code>.
</p>

<p>
	باستدعاء <code>Date.parse(str)</code> فالسلسلة النصية تُحلّل حسب التنسيق فيها ويُعيد التابِع الختم الزمني (رقم المليثوان منذ الأول من يناير 1970 بتوقيت UTC+0). لو كان التنسيق غير صحيح فيُعيد <code>NaN</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_52" style="">
<span class="pln">let ms </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span class="str">'2012-01-26T13:51:50.417-07:00'</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">ms</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫1327611110417 (ختم زمني)</span></pre>

<p>
	يمكننا إنشاء كائن <code>new Date</code> مباشرةً من الختم الزمني:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_54" style="">
<span class="pln">let date </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="typ">Date</span><span class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span class="str">'2012-01-26T13:51:50.417-07:00'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">date</span><span class="pun">);</span><span class="pln">  </span></pre>

<h2>
	ملخص
</h2>

<ul>
<li>
		يُمثّل التاريخ والوقت في جافاسكربت بكائن <a href="https://wiki.hsoub.com/JavaScript/Date" rel="external">Date</a>. لا يمكننا إنشاء ”تاريخ فقط“ أو ”وقتًا فقط“، فعلى كائنات التاريخ <code>Date</code> احتواء الاثنين معًا.
	</li>
	<li>
		تُعدّ الأشهر بدءًا بالصفر (يناير هو الشهر صفر، نعم).
	</li>
	<li>
		يُعدّ رقم اليوم من الأسبوع في <code>getDay()‎</code> من الصفر أيضًا (وهو يوم الأحد).
	</li>
	<li>
		يصحّح كائن التاريخ نفسه تلقائيًا حين تُضبط مكوّناته بقيم لا منطقية. يفيدنا لجمع/طرح الأيام والأشهر والأعوام.
	</li>
	<li>
		يمكن طرح التواريخ ومعرفة الفرق بينها بالمليثانية، ذلك لأنّ كائن التاريخ يتحوّل إلى ختم زمني حين يتحوّل إلى عدد.
	</li>
	<li>
		استعمل <code>Date.now()‎</code> لو أردت جلب الختم الزمني الحالي بسرعة.
	</li>
</ul>
<p>
	لاحظ بأنّ الأختام الزمنية في جافاسكربت هي بالمليثانية، على العكس من أنظمة عديدة أخرى.
</p>

<p>
	نجد نفسنا بين الحين والآخر قياسات وقت دقيقة. للأسف فلا توفّر جافاسكربت نفسها طريقة لحساب الوقت بالنانوثانية (1 على مليون من الثانية)، ولكن أغلب بيئاتها توفّر ذلك. فمثلًا تملك المتصفّحات التابِع <a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance/now" rel="external nofollow">performance.now()‎</a> إذ يُعيد عدد المليثوان منذ بدأ تحميل الصفحة بقدّة تصل إلى المايكروثانية (ثلاث خانات بعد الفاصلة):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_56" style="">
<span class="pln">alert</span><span class="pun">(`</span><span class="typ">Loading</span><span class="pln"> started $</span><span class="pun">{</span><span class="pln">performance</span><span class="pun">.</span><span class="pln">now</span><span class="pun">()}</span><span class="pln">ms ago</span><span class="pun">`);</span><span class="pln">
</span><span class="com">// "Loading started 34731.26000000001ms ago"</span></pre>

<p>
	تعني ”‎.26“ هنا المايكروثوان (260 مايكروثانية)، فلو زِدت على ثلاث خانات بعد الفاصلة فستجد أخطاءً في دقّة الحساب. أوّل ثلاثة هي الصحيحة فقط.
</p>

<p>
	تملك لغة Node.js أيضًا وحدة <code>microtime</code> وأخرى غيرها. يمكن (تقنيًا) لأيّ جهاز أو بيئة أن تعطينا دقّة وقت أعلى، <code>Date</code> لا تقدّم ذلك لا أكثر.
</p>

<h2>
	تمارين
</h2>

<h3>
	إنشاء تاريخ
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	أنشِئ كائن <code>Date</code> لهذا التاريخ: 20 فبراير 2012، 3:12 صباحًا. المنطقة الزمنية هي المحلية. اعرض التاريخ باستعمال <code>alert</code>.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		يستعمل مُنشِئ <code>new Date</code> المنطقة الزمنية الحالية. عليك ألا تنسى بأنّ الأشهر تبدأ من الصفر.
	</p>

	<p>
		إذًا ففبراير هو الشهر رقم 1.
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_58" style="">
<span class="pln">let d </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">2012</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">20</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">12</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> d </span><span class="pun">);</span></pre>
</div>

<h3>
	اعرض اسم اليوم من الأسبوع
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	اكتب دالة <code>getWeekDay(date)‎</code> تعرض اسم اليوم من الأسبوع بالتنسيق الإنكليزي القصير: 'MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU'.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_60" style="">
<span class="pln">let date </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">2012</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">3</span><span class="pun">);</span><span class="pln">  </span><span class="com">// ‫3 يناير 2012</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getWeekDay</span><span class="pun">(</span><span class="pln">date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">        </span><span class="com">// ي‫جب أن يطبع "TU"</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		يُعيد التابِع <code>date.getDay()‎</code> رقم اليوم من الأسبوع، بدءًا من يوم الأحد.
	</p>

	<p>
		لنصنع مصفوفة فيها أيام الأسبوع لنعرف اليوم الصحيح من رقمه:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_62" style="">
<span class="kwd">function</span><span class="pln"> getWeekDay</span><span class="pun">(</span><span class="pln">date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let days </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'SU'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'MO'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'TU'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'WE'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'TH'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'FR'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'SA'</span><span class="pun">];</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> days</span><span class="pun">[</span><span class="pln">date</span><span class="pun">.</span><span class="pln">getDay</span><span class="pun">()];</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let date </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">2014</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">3</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫3 يناير 2014</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getWeekDay</span><span class="pun">(</span><span class="pln">date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// FR</span></pre>
</div>

<h3>
	اليوم من الأسبوع في أوروبا
</h3>

<p class="task__importance">
	<em>الأهمية: 4</em>
</p>

<p>
	في الدول الأوروبية، يبدأ الأسبوع بيوم الإثنين (رقم 1) وثمّ الثلاثاء (رقم 2) وحتّى الأحد (رقم 7). اكتب دالة <code>getLocalDay(date)</code> تُعيد يوم الأسبوع ”الأوروبي“ من التاريخ <code>date</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_64" style="">
<span class="pln">let date </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">2012</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">3</span><span class="pun">);</span><span class="pln">  </span><span class="com">// ‫3 يناير 2012</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getLocalDay</span><span class="pun">(</span><span class="pln">date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">       </span><span class="com">// يكون يوم ثلاثاء، يجب أن تعرض 2</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_66" style="">
<span class="kwd">function</span><span class="pln"> getLocalDay</span><span class="pun">(</span><span class="pln">date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  let day </span><span class="pun">=</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getDay</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">day </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="com">// يوم الأحد 0 في أوروبا هو الأخير (7)‏</span><span class="pln">
    day </span><span class="pun">=</span><span class="pln"> </span><span class="lit">7</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"> day</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>
</div>

<h3>
	ما هو التاريخ الذي كان قبل كذا يوم؟
</h3>

<p class="task__importance">
	<em>الأهمية: 4</em>
</p>

<p>
	أنشِئ دالة <code>getDateAgo(date, days)‎</code> تُعيد بتمرير التاريخ <code>date</code> اسم اليوم من الشهر قبل فترة <code>days</code> يوم.
</p>

<p>
	مثال: لو كان اليوم العشرون من الشهر، فتُعيد <code>getDateAgo(new Date(),1 )‎</code> التاسع عشر و<code>getDateAgo(new Date(), 2)‎</code> الثامن عشر.
</p>

<p>
	يجب أن نعوّل بأن تعمل الدالة في حال <code>days=356</code> وأكثر حتّى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_68" style="">
<span class="pln">let date </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">2015</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="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> getDateAgo</span><span class="pun">(</span><span class="pln">date</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫1، (1 يناير 2015)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getDateAgo</span><span class="pun">(</span><span class="pln">date</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="com">// ‫31، (31 ديسمبر 2014)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getDateAgo</span><span class="pun">(</span><span class="pln">date</span><span class="pun">,</span><span class="pln"> </span><span class="lit">365</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫2، (2 يناير 2014)</span></pre>

<p>
	ملاحظة: يجب ألّا تُعدّل الدالة التاريخ <code>date</code> المُمرّر.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		الفكرة بسيطة، أن نطرح عدد الأيام من التاريخ <code>date</code>:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_70" style="">
<span class="kwd">function</span><span class="pln"> getDateAgo</span><span class="pun">(</span><span class="pln">date</span><span class="pun">,</span><span class="pln"> days</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  date</span><span class="pun">.</span><span class="pln">setDate</span><span class="pun">(</span><span class="pln">date</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> days</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

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

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_72" style="">
<span class="kwd">function</span><span class="pln"> getDateAgo</span><span class="pun">(</span><span class="pln">date</span><span class="pun">,</span><span class="pln"> days</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let dateCopy </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">date</span><span class="pun">);</span><span class="pln">

  dateCopy</span><span class="pun">.</span><span class="pln">setDate</span><span class="pun">(</span><span class="pln">date</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> days</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> dateCopy</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let date </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">2015</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="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> getDateAgo</span><span class="pun">(</span><span class="pln">date</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫1، (1 يناير 2015)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getDateAgo</span><span class="pun">(</span><span class="pln">date</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="com">// ‫31، (31 ديسمبر 2014)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getDateAgo</span><span class="pun">(</span><span class="pln">date</span><span class="pun">,</span><span class="pln"> </span><span class="lit">365</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫2، (2 يناير 2014)</span></pre>
</div>

<h3>
	آخر يوم من الشهر كذا؟
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	اكتب دالة <code>getLastDayOfMonth(year, month)‎</code> تُعيد آخر يوم من الشهر. أحيانًا يكون الثلاثين، أو الحادي والثلاثين أو الثامن/التاسع عشر من فبراير.
</p>

<p>
	المُعاملات:
</p>

<ul>
<li>
		<code>year</code> -- العام بأربع خانات، مثلًا 2012.
	</li>
	<li>
		<code>month</code> -- الشهر من 0 إلى 11.
	</li>
</ul>
<p>
	مثال: <code>getLastDayOfMonth(2012, 1) = 29</code> (سنة كبيسة، فبراير).
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		فلنصنع تاريخًا باستعمال الشهر التالي، ولكنّ نمرّر الصفر ليكون رقم اليوم:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_74" style="">
<span class="kwd">function</span><span class="pln"> getLastDayOfMonth</span><span class="pun">(</span><span class="pln">year</span><span class="pun">,</span><span class="pln"> month</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let date </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">year</span><span class="pun">,</span><span class="pln"> month </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">0</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> getLastDayOfMonth</span><span class="pun">(</span><span class="lit">2012</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="com">// 31</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getLastDayOfMonth</span><span class="pun">(</span><span class="lit">2012</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 29</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getLastDayOfMonth</span><span class="pun">(</span><span class="lit">2013</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 28</span></pre>

	<p>
		عادةً ما تبدأ التواريخ بالواحد، لكن يمكننا (تقنيًا) تمرير أيّ عدد وسيُعدّل التاريخ نفسه. لذا حين نمرّر 0 نعني بذلك ”يومًا واحد قبل الأول من الشهر“، أي ”اليوم الأخير من الشهر الماضي“.
	</p>
</div>

<h3>
	كم من ثانية مضت اليوم؟
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	اكتب دالة <code>getSecondsToday()‎</code> تُعيد عدد الثواني منذ بداية هذا اليوم. فمثلًا لو كانت الساعة الآن <code>10:00 am</code>، وبدون التوقيت الصيفي، فستعطينا الدالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_76" style="">
<span class="pln">getSecondsToday</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">36000</span><span class="pln"> </span><span class="com">// (3600 * 10)</span></pre>

<p>
	يجب أن تعمل الدالة مهما كان اليوم. أيّ ألا تحتوي على قيمة داخلها بتاريخ ”اليوم“… اليوم.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		لنعرف عدد الثواني يمكننا توليد تاريخًا باستعمال اليوم الحالي والساعة 00:00:00، وثمّ نطرح منها ”الوقت والتاريخ الآن“. سيكون الفرق حينها بعدد المليثوان منذ بداية هذا اليوم، فنقسمه على 1000 لنعرف الثواني فقط:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_78" style="">
<span class="kwd">function</span><span class="pln"> getSecondsToday</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let now </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="com">// أنشِئ كائنًا باستعمال اليوم والشهر والسنة حاليًا</span><span class="pln">
  let today </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">now</span><span class="pun">.</span><span class="pln">getFullYear</span><span class="pun">(),</span><span class="pln"> now</span><span class="pun">.</span><span class="pln">getMonth</span><span class="pun">(),</span><span class="pln"> now</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">());</span><span class="pln">

  let diff </span><span class="pun">=</span><span class="pln"> now </span><span class="pun">-</span><span class="pln"> today</span><span class="pun">;</span><span class="pln"> </span><span class="com">// الفرق بالمليثانية</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">round</span><span class="pun">(</span><span class="pln">diff </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">// نحوّله إلى ثوان</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> getSecondsToday</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_9830_80" style="">
<span class="kwd">function</span><span class="pln"> getSecondsToday</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let d </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">return</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">getHours</span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">3600</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">getMinutes</span><span class="pun">()</span><span class="pln"> </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"> d</span><span class="pun">.</span><span class="pln">getSeconds</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>
</div>

<h3>
	كم من ثانية بقت حتّى الغد؟
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	أنشِئ دالة <code>getSecondsToTomorrow()‎</code> تُعيد عدد الثواني حتّى يحلّ الغد. فمثلًا لو كان الوقت الآن <code>23:00</code>، تُعيد لنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_82" style="">
<span class="pln">getSecondsToTomorrow</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3600</span></pre>

<p>
	ملاحظة: يجب أن تعمل الدالة مهما كان اليوم، وألا تعتبر ”اليوم“ هذا اليوم.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		لنعرف عدد المليثوان حتّى قدوم الغد، يمكننا أن نطرح من ”الغد 00:00:00“ التاريخ اليوم. أوّلًا، نولّد هذا ”الغد“ وثمّ ننفّذ الطرح:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_84" style="">
<span class="kwd">function</span><span class="pln"> getSecondsToTomorrow</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let now </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="com">// تاريخ الغد</span><span class="pln">
  let tomorrow </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">now</span><span class="pun">.</span><span class="pln">getFullYear</span><span class="pun">(),</span><span class="pln"> now</span><span class="pun">.</span><span class="pln">getMonth</span><span class="pun">(),</span><span class="pln"> now</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">()+</span><span class="lit">1</span><span class="pun">);</span><span class="pln">

  let diff </span><span class="pun">=</span><span class="pln"> tomorrow </span><span class="pun">-</span><span class="pln"> now</span><span class="pun">;</span><span class="pln"> </span><span class="com">// الفرق بالمليثانية</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">round</span><span class="pun">(</span><span class="pln">diff </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">// نحوّله إلى ثوان</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		حل بديل:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_86" style="">
<span class="kwd">function</span><span class="pln"> getSecondsToTomorrow</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let now </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">
  let hour </span><span class="pun">=</span><span class="pln"> now</span><span class="pun">.</span><span class="pln">getHours</span><span class="pun">();</span><span class="pln">
  let minutes </span><span class="pun">=</span><span class="pln"> now</span><span class="pun">.</span><span class="pln">getMinutes</span><span class="pun">();</span><span class="pln">
  let seconds </span><span class="pun">=</span><span class="pln"> now</span><span class="pun">.</span><span class="pln">getSeconds</span><span class="pun">();</span><span class="pln">
  let totalSecondsToday </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">hour </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"> minutes</span><span class="pun">)</span><span class="pln"> </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"> seconds</span><span class="pun">;</span><span class="pln">
  let totalSecondsInADay </span><span class="pun">=</span><span class="pln"> </span><span class="lit">86400</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> totalSecondsInADay </span><span class="pun">-</span><span class="pln"> totalSecondsToday</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		لاحظ أنّ هناك دولًا كثيرة تستعمل التوقيت الصيفي، لذا ستجد هناك أيام فيها 23 أو 25 ساعة. يمكن أن نتعامل مع هذه الأيام بنحوٍ منفصل.
	</p>
</div>

<h3>
	تنسيق التاريخ نسبيًا
</h3>

<p class="task__importance">
	<em>الأهمية: 4</em>
</p>

<p>
	اكتب دالة <code>formatDate(date)‎</code> تُنسّق التاريخ <code>date</code> حسب الآتي:
</p>

<ul>
<li>
		لو مرّت أقلّ من ثانية من <code>date</code>، فتُعيد <code>"right now"</code>.
	</li>
	<li>
		وإلّا، لو مرّت أقلّ من دقيقة من <code>date</code>، فتُعيد <code>"n sec. ago"</code>.
	</li>
	<li>
		وإلّا، لو أقل من ساعة، فتُعيد <code>"m min. ago"</code>.
	</li>
	<li>
		وإلّا، فتُعيد التاريخ كاملًا بالتنسيق <code>"DD.MM.YY HH:mm"</code>، أي (شَكلًا): <code>الدقيقة:الساعة العام:الشهر:اليوم</code> (كلها بخانتين). مثل: <code>31.12.16 10:00</code>.
	</li>
</ul>
<p>
	أمثلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_88" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> formatDate</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</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="com">// "right now"</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> formatDate</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">30</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"> </span><span class="com">// "30 sec. ago"</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> formatDate</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">60</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"> </span><span class="com">// "5 min. ago"</span><span class="pln">

</span><span class="com">// ‫تاريخ الأمس، مثلًا ‎31.12.16, 20:00</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> formatDate</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">86400</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></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		لنجلب الوقت المنقضي منذ <code>date</code> وحتّى الآن، سنطرح التاريخين.
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_90" style="">
<span class="kwd">function</span><span class="pln"> formatDate</span><span class="pun">(</span><span class="pln">date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let diff </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="pun">-</span><span class="pln"> date</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">diff </span><span class="pun">&lt;</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"> </span><span class="com">// أقل من ثانية واحدة</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'right now'</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  let sec </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="pln">diff </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">// نحوّل الفرق إلى ثوان</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">sec </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">60</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"> sec </span><span class="pun">+</span><span class="pln"> </span><span class="str">' sec. ago'</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  let min </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="pln">diff </span><span class="pun">/</span><span class="pln"> </span><span class="lit">60000</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">min </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">60</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"> min </span><span class="pun">+</span><span class="pln"> </span><span class="str">' min. ago'</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// ننسّق التاريخ</span><span class="pln">
  </span><span class="com">// ونُضيف أصفارًا لو كان اليوم/الشهر/الساعة/الدقيقة بخانة واحدة</span><span class="pln">
  let d </span><span class="pun">=</span><span class="pln"> date</span><span class="pun">;</span><span class="pln">
  d </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">'0'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">(),</span><span class="pln">
    </span><span class="str">'0'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="pln">d</span><span class="pun">.</span><span class="pln">getMonth</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">),</span><span class="pln">
    </span><span class="str">''</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">getFullYear</span><span class="pun">(),</span><span class="pln">
    </span><span class="str">'0'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">getHours</span><span class="pun">(),</span><span class="pln">
    </span><span class="str">'0'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">getMinutes</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">].</span><span class="pln">map</span><span class="pun">(</span><span class="pln">component </span><span class="pun">=&gt;</span><span class="pln"> component</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">// نأخذ الخانتين الأخيرتين من كلّ مكوّن</span><span class="pln">

  </span><span class="com">// ندمج المكوّنات في تاريخ</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</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="pun">+</span><span class="pln"> </span><span class="str">' '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">(</span><span class="lit">3</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="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> formatDate</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</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="com">// "right now"</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> formatDate</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">30</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"> </span><span class="com">// "30 sec. ago"</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> formatDate</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">60</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"> </span><span class="com">// "5 min. ago"</span><span class="pln">

</span><span class="com">// ‫تاريخ الأمس، مثلًا ‎31.12.16, 20:00</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> formatDate</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">86400</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></pre>

	<p>
		حل بديل:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9830_92" style="">
<span class="kwd">function</span><span class="pln"> formatDate</span><span class="pun">(</span><span class="pln">date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let dayOfMonth </span><span class="pun">=</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">();</span><span class="pln">
  let month </span><span class="pun">=</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getMonth</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">
  let year </span><span class="pun">=</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getFullYear</span><span class="pun">();</span><span class="pln">
  let hour </span><span class="pun">=</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getHours</span><span class="pun">();</span><span class="pln">
  let minutes </span><span class="pun">=</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getMinutes</span><span class="pun">();</span><span class="pln">
  let diffMs </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="pun">-</span><span class="pln"> date</span><span class="pun">;</span><span class="pln">
  let diffSec </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">round</span><span class="pun">(</span><span class="pln">diffMs </span><span class="pun">/</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
  let diffMin </span><span class="pun">=</span><span class="pln"> diffSec </span><span class="pun">/</span><span class="pln"> </span><span class="lit">60</span><span class="pun">;</span><span class="pln">
  let diffHour </span><span class="pun">=</span><span class="pln"> diffMin </span><span class="pun">/</span><span class="pln"> </span><span class="lit">60</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// التنسيق</span><span class="pln">
  year </span><span class="pun">=</span><span class="pln"> year</span><span class="pun">.</span><span class="pln">toString</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">
  month </span><span class="pun">=</span><span class="pln"> month </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">'0'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> month </span><span class="pun">:</span><span class="pln"> month</span><span class="pun">;</span><span class="pln">
  dayOfMonth </span><span class="pun">=</span><span class="pln"> dayOfMonth </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">'0'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> dayOfMonth </span><span class="pun">:</span><span class="pln"> dayOfMonth</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">diffSec </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'right now'</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">diffMin </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">diffSec</span><span class="pun">}</span><span class="pln"> sec</span><span class="pun">.</span><span class="pln"> ago</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">diffHour </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">diffMin</span><span class="pun">}</span><span class="pln"> min</span><span class="pun">.</span><span class="pln"> ago</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">return</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">dayOfMonth</span><span class="pun">}.</span><span class="pln">$</span><span class="pun">{</span><span class="pln">month</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="pun">{</span><span class="pln">hour</span><span class="pun">}:</span><span class="pln">$</span><span class="pun">{</span><span class="pln">minutes</span><span class="pun">}`</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		لاحظ بأنّ هذه الطريقة سيّئة لو أردت دعم اللغات دعمًا صحيحًا (في العربية هناك ثانية واحدة وثانيتين وثلاث ثوان وخمسون ثانية وهكذا).
	</p>
</div>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
<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-r826/" rel="">صيغة JSON وتوابعها</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A5%D8%B3%D9%86%D8%A7%D8%AF-%D8%A8%D8%A7%D9%84%D8%AA%D9%81%D9%83%D9%8A%D9%83-destructuring-assignment-r824/" rel="">الإسناد بالتفكيك (Destructuring assignment)</a>
	</li>
</ul>
<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/date" rel="external nofollow">Date and time</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">825</guid><pubDate>Sun, 23 Feb 2020 11:45:22 +0000</pubDate></item><item><title>&#x627;&#x644;&#x625;&#x633;&#x646;&#x627;&#x62F; &#x628;&#x627;&#x644;&#x62A;&#x641;&#x643;&#x64A;&#x643; (Destructuring assignment) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A5%D8%B3%D9%86%D8%A7%D8%AF-%D8%A8%D8%A7%D9%84%D8%AA%D9%81%D9%83%D9%8A%D9%83-destructuring-assignment-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r824/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/41.jpg.9fa6ef799851773e2845c4967ab5eaa2.jpg" /></p>

<p>
	﻿في جافاسكربت، الكائنات والمصفوفات هي أكثر بنى البيانات المستعملة. تُتيح لنا الكائنات إنشاء كيان واحد يُخزّن عناصر البيانات حسب مفاتيحها، وتُتيح لنا المصفوفات بجمع مختلف عناصر البيانات في تجميعة مرتّبة (ordered collection).
</p>

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

<p>
	صياغة <em>الإسناد بالتفكيك</em> (<em>Destructuring assignment)</em> هي صياغة خاصّة تُتيح لنا ”فكّ“ المصفوفات أو الكائنات إلى مجموعة من المتغيرات إذ تكون أحيانًا أكثر منطقية. يفيدنا التفكيك أيضًا مع الدوال المعقّدة التي تحتوي على مُعاملات كثيرة وقيم مبدئية وغيرها وغيرها.
</p>

<h2>
	تفكيك المصفوفات
</h2>

<p>
	إليك مثال عن تفكيك مصفوفة إلى مجموعة من المتغيرات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_7" style="">
<span class="com">// معنا مصفوفة فيها اسم الشخص واسم عائلته</span><span class="pln">
let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Ilya"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Kantor"</span><span class="pun">]</span><span class="pln">

</span><span class="com">// يضبط الإسناد بالتفكيك</span><span class="pln">
</span><span class="com">// ‫هذه firstName = arr[0]‎</span><span class="pln">
</span><span class="com">// ‫وهذه surname = arr[1]‎</span><span class="pln">
let </span><span class="pun">[</span><span class="pln">firstName</span><span class="pun">,</span><span class="pln"> surname</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">firstName</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Ilya</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">surname</span><span class="pun">);</span><span class="pln">  </span><span class="com">// Kantor</span></pre>

<p>
	يمكننا الآن العمل مع تلك المتغيرات عوض عناصر المصفوفة. وما إن تجمع تابِع <code>split</code> وغيرها من توابِع تُعيد مصفوفات، سترى بريق هذا التفكيك يتألق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_11" style="">
<span class="pln">let </span><span class="pun">[</span><span class="pln">firstName</span><span class="pun">,</span><span class="pln"> surname</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Ilya Kantor"</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">' '</span><span class="pun">);</span></pre>

<p>
	<strong>”التفكيك“ (Destructuring) لا يعني ”التكسير“ (destructive)</strong>
</p>

<p>
	نُسمّيه "الإسناد بالتفكيك" (destructuring assignment) لأنّه "يفكّك" العناصر بنسخها إلى متغيرات. أمّا المصفوفة نفسها فتبقى دون تعديل.
</p>

<p>
	كتابة هذه الشيفرة أسهل من تلك الطويلة (ندعها لك تتخيّلها):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_9" style="">
<span class="com">// let [firstName, surname] = arr;</span><span class="pln">
let firstName </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">
let surname </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">[</span><span class="lit">1</span><span class="pun">];</span></pre>

<p>
	<strong>أهمِل العناصر باستعمال الفواصل</strong> يمكنك ”رمي“ وتجاهل العناصر التي لا تريدها بإضافة فاصلة أخرى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_13" style="">
<span class="com">// لا نريد العنصر الثاني</span><span class="pln">
let </span><span class="pun">[</span><span class="pln">firstName</span><span class="pun">,</span><span class="pln"> </span><span class="pun">,</span><span class="pln"> title</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Julius"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Caesar"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Consul"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"of the Roman Republic"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> title </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Consul</span></pre>

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

<p>
	<strong>تعمل الميزة مع المُتعدَّدات حين تكون على اليمين</strong>
</p>

<p>
	…الواقع هو أنّنا نستطيع استعمالها مع أيّ مُكرَّر وليس المصفوفات فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_15" style="">
<span class="pln">let </span><span class="pun">[</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"abc"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ["a", "b", "c"]</span><span class="pln">
let </span><span class="pun">[</span><span class="pln">one</span><span class="pun">,</span><span class="pln"> two</span><span class="pun">,</span><span class="pln"> three</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Set</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></pre>

<p>
	<strong>أسنِدها إلى ما تريد على اليسار</strong>
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_17" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln">
</span><span class="pun">[</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">surname</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Ilya Kantor"</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">

alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Ilya</span></pre>

<p>
	<strong>المرور على العناصر عبر <code>‎.entries()‎</code></strong>
</p>

<p>
	رأينا في الفصل الماضي التابِع <a href="https://wiki.hsoub.com/JavaScript/Object/entries" rel="external">Object.entries(obj)</a><strong><code>‎</code></strong>. يمكننا استعماله مع التفكيك للمرور على مفاتيح الكائنات وقيمها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_19" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// نمرّ على المفاتيح والقيم</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let </span><span class="pun">[</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">]</span><span class="pln"> of </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">entries</span><span class="pun">(</span><span class="pln">user</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">key</span><span class="pun">}:</span><span class="pln">$</span><span class="pun">{</span><span class="pln">value</span><span class="pun">}`);</span><span class="pln"> </span><span class="com">// name:John, then age:30</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	…وذات الأمر للخارطة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_21" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">();</span><span class="pln">
user</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"name"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">);</span><span class="pln">
user</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"age"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"30"</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let </span><span class="pun">[</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">]</span><span class="pln"> of user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">key</span><span class="pun">}:</span><span class="pln">$</span><span class="pun">{</span><span class="pln">value</span><span class="pun">}`);</span><span class="pln"> </span><span class="com">// name:John, then age:30</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	الباقي ”…“
</h3>

<p>
	لو أردنا أخذ القيم الأولى إضافةً إلى كل ما يليها، فنُضيف مُعاملًا آخر يجلب ”الباقي“ باستعمال ثلاث نقاط <code>"..."</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_23" style="">
<span class="pln">let </span><span class="pun">[</span><span class="pln">name1</span><span class="pun">,</span><span class="pln"> name2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">rest</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Julius"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Caesar"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Consul"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"of the Roman Republic"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">name1</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Julius</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">name2</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Caesar</span><span class="pln">

</span><span class="com">// ‫انتبه أنّ المتغير rest مصفوفة.</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">rest</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]);</span><span class="pln"> </span><span class="com">// Consul</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">rest</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]);</span><span class="pln"> </span><span class="com">// of the Roman Republic</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">rest</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span></pre>

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

<h3>
	القيم المبدئية
</h3>

<p>
	لو كانت القيم في المصفوفة أقلّ من تلك في جملة الإسناد فلن يحدث أيّ خطأ. يُعدّ المحرّك القيم ”الغائبة“ غير معرّفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_25" style="">
<span class="pln">let </span><span class="pun">[</span><span class="pln">firstName</span><span class="pun">,</span><span class="pln"> surname</span><span class="pun">]</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="pln">firstName</span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">surname</span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined</span></pre>

<p>
	لو أردنا قيمة مبدئية تعوّض تلك الناقصة فيمكننا تقديمها باستعمال <code>=</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_27" style="">
<span class="com">// القيم المبدئية</span><span class="pln">
let </span><span class="pun">[</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Guest"</span><span class="pun">,</span><span class="pln"> surname </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Anonymous"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Julius"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">name</span><span class="pun">);</span><span class="pln">    </span><span class="com">// ‫Julius (من المصفوفة)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">surname</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫Anonymous (المبدئي)</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_29" style="">
<span class="com">// ‫لا تطلب إلا اسم العائلة surname</span><span class="pln">
let </span><span class="pun">[</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">'name?'</span><span class="pun">),</span><span class="pln"> surname </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">'surname?'</span><span class="pun">)]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Julius"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">name</span><span class="pun">);</span><span class="pln">    </span><span class="com">// ‫Julius (نأخذه من المصفوفة)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">surname</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫نحترم هنا ما يقول promot</span></pre>

<h2>
	تكفيك الكائنات
</h2>

<p>
	الإسناد بالتفكيك يدعم أيضًا الكائنات. هذه صياغته الأساس:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_31" style="">
<span class="pln">let </span><span class="pun">{</span><span class="pln">var1</span><span class="pun">,</span><span class="pln"> var2</span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">var1</span><span class="pun">:…,</span><span class="pln"> var2</span><span class="pun">:…}</span></pre>

<p>
	على اليمين الكائن الموجود والذي نريد تقسيمه على عدّة متغيرات، وعلى اليسار نضع ”نمط“ الخاصيات المقابِلة له. لو كان الكائن بسيطًا، فهذا النمط هو قائمة باسم المتغيرات داخل <code>{...}</code>. مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_33" style="">
<span class="pln">let options </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pun">,</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">200</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let </span><span class="pun">{</span><span class="pln">title</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="pun">=</span><span class="pln"> options</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">title</span><span class="pun">);</span><span class="pln">  </span><span class="com">// Menu</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">width</span><span class="pun">);</span><span class="pln">  </span><span class="com">// 100</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">height</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 200</span></pre>

<p>
	تُسند الخاصيات <code>options.title</code> و<code>options.width</code> و<code>options.height</code> إلى المتغيرات المقابِلة لها. كما وأنّ الترتيب غير مهم: يمكنك فعل هذا أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_35" style="">
<span class="com">// ‫غيّرنا الترتيب داخل ‪let {...}</span><span class="pln">
let </span><span class="pun">{</span><span class="pln">height</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	يمكن أن يكون النمط على اليسار معقّدًا أكثر ومُحدّدًا فيحدّد طريقة ترابط الخاصيات بالمتغيرات عبر الخارطة (mapping).
</p>

<p>
	لو أردنا إسناد خاصية إلى متغير له اسم آخر فعلينا استعمال النقطتين الرأسيتين لذلك (مثلًا <code>options.width</code> يصير في المتغير <code>w</code>):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_37" style="">
<span class="pln">let options </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pun">,</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">200</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// { sourceProperty: targetVariable }</span><span class="pln">
let </span><span class="pun">{</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> w</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">:</span><span class="pln"> h</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> options</span><span class="pun">;</span><span class="pln">

</span><span class="com">// width -&gt; w</span><span class="pln">
</span><span class="com">// height -&gt; h</span><span class="pln">
</span><span class="com">// title -&gt; title</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">title</span><span class="pun">);</span><span class="pln">  </span><span class="com">// Menu</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">w</span><span class="pun">);</span><span class="pln">      </span><span class="com">// 100</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">h</span><span class="pun">);</span><span class="pln">      </span><span class="com">// 200</span></pre>

<p>
	تعني النقطتان الرأسيتان ”هذا : يصير هذا“. في المثال أعلاه، تصير الخاصية <code>width</code> بالاسم <code>w</code>، والخاصية <code>height</code> بالاسم <code>h</code> والخاصية <code>title</code> كما هي <code>title</code>.
</p>

<p>
	يمكننا هنا أيضًا وضع قيمة مبدئية للخاصيات الناقصة باستعمال <code>"="</code> هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_39" style="">
<span class="pln">let options </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let </span><span class="pun">{</span><span class="pln">width </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> height </span><span class="pun">=</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> options</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">title</span><span class="pun">);</span><span class="pln">  </span><span class="com">// Menu</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">width</span><span class="pun">);</span><span class="pln">  </span><span class="com">// 100</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">height</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 200</span></pre>

<p>
	كما يمكن أن تكون هذه القيم المبدئية أيّة تعابير أو استدعاءات دوال كما مقابلاتها في المصفوفات ومُعاملات الدوال، ولن يقدّر المحرّك قيمتها إلّا لو لم تقدّم قيمة للدالة.
</p>

<p>
	في الشيفرة أدناه، تطلب الدالة <code>promot</code> قيمة <code>width</code> ولا تطلب قيمة <code>title</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_43" style="">
<span class="pln">let options </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="pun">*!*</span><span class="pln">
let </span><span class="pun">{</span><span class="pln">width </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"width?"</span><span class="pun">),</span><span class="pln"> title </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"title?"</span><span class="pun">)}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> options</span><span class="pun">;</span><span class="pln">
</span><span class="pun">*/!*</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">title</span><span class="pun">);</span><span class="pln">  </span><span class="com">// Menu</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">width</span><span class="pun">);</span><span class="pln">  </span><span class="com">// (promot هنا نحترم أيضًا ما يقول)</span></pre>

<p>
	يمكننا أيضًا جمع النقطتان الرأسيتان والقيم المبدئية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_45" style="">
<span class="pln">let options </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let </span><span class="pun">{</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> w </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">:</span><span class="pln"> h </span><span class="pun">=</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> options</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">title</span><span class="pun">);</span><span class="pln">  </span><span class="com">// Menu</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">w</span><span class="pun">);</span><span class="pln">      </span><span class="com">// 100</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">h</span><span class="pun">);</span><span class="pln">      </span><span class="com">// 200</span></pre>

<p>
	لو كان لدينا كائنًا معقّدًا فيه خاصيات كثيرة، فيمكننا استخراج ما نريد منه فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_47" style="">
<span class="pln">let options </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pun">,</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">200</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// ‫استخرج العنوان title ليكون متغيرًا هو فقط</span><span class="pln">
let </span><span class="pun">{</span><span class="pln"> title </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> options</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">title</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Menu</span></pre>

<h3>
	نمط الباقي ”…“
</h3>

<p>
	ماذا لو كان للكائن خاصيات أكثر من المتغيرات التي لدينا؟ هل يمكننا أخذها وإسنادها في متغيّر ”rest“ أيضًا؟
</p>

<p>
	أجل يمكننا استعمال نمط الباقي تمامًا مثل المصفوفات. بعض المتصفحات القديمة لا تدعمه (مثل إنترنت إكسبلورر، استعمل Babel لترقيعه polyfill، أي لتعويض نقص الدعم)، إلّا أن الحديثة تدعمه.
</p>

<p>
	هكذا نفعلها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_49" style="">
<span class="pln">let options </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pun">,</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// ‫title = خاصية بالاسم title</span><span class="pln">
</span><span class="com">// ‫rest = كائن فيه باقي الخاصيات</span><span class="pln">
let </span><span class="pun">{</span><span class="pln">title</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">rest</span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> options</span><span class="pun">;</span><span class="pln">

</span><span class="com">// ‫صار الآن title="Menu", rest={height: 200, width: 100}</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">rest</span><span class="pun">.</span><span class="pln">height</span><span class="pun">);</span><span class="pln">  </span><span class="com">// 200</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">rest</span><span class="pun">.</span><span class="pln">width</span><span class="pun">);</span><span class="pln">   </span><span class="com">// 100</span></pre>

<p>
	<strong>انتبه لو لم تضع <code>let</code></strong> في المثال أعلاه، صرّحنا عن المتغيرات على يمين جملة الإسناد: <code>let {…} = {…}‎</code>. يمكننا طبعًا استعمال متغيرات موجودة دون <code>let</code>، ولكن هناك أمر، فهذا لن يعمل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_51" style="">
<span class="pln">let title</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="com">// سترى خطأ في هذا السطر</span><span class="pln">
</span><span class="pun">{</span><span class="pln">title</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="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">};</span></pre>

<p>
	المشكلة هي أنّ جافاسكربت تتعامل مع <code>{...}</code> في سياق الشيفرة الأساس (أي ليس داخل تعبير آخر) على أنّها بنية شيفرة (Code Block). يمكن استعمال بنى الشيفرة هذه لجمع التعليمات البرمجية، هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_53" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// بنية شيفرة</span><span class="pln">
  let message </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> message </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_55" style="">
<span class="pln">let title</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="com">// الآن جيد</span><span class="pln">
</span><span class="pun">({</span><span class="pln">title</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="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">});</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> title </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Menu</span></pre>

<h2>
	تفكيك المتغيرات المتداخلة
</h2>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_57" style="">
<span class="pln">let options </span><span class="pun">=</span><span class="pln"> </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">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">200</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  items</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Cake"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Donut"</span><span class="pun">],</span><span class="pln">
  extra</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">   
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// نقسم الإسناد بالتفكيك على أكثر من سطر لتوضيح العملية</span><span class="pln">
let </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="com">// هنا يكون المقاس</span><span class="pln">
    width</span><span class="pun">,</span><span class="pln">
    height
  </span><span class="pun">},</span><span class="pln">
  items</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">item1</span><span class="pun">,</span><span class="pln"> item2</span><span class="pun">],</span><span class="pln"> </span><span class="com">// وهنا نضع العناصر</span><span class="pln">
  title </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pln"> </span><span class="com">// ليست موجودة في الكائن (ستُستعمل القيمة المبدئية)‏</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> options</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">title</span><span class="pun">);</span><span class="pln">  </span><span class="com">// Menu</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">width</span><span class="pun">);</span><span class="pln">  </span><span class="com">// 100</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">height</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 200</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">item1</span><span class="pun">);</span><span class="pln">  </span><span class="com">// Cake</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">item2</span><span class="pun">);</span><span class="pln">  </span><span class="com">// Donut</span></pre>

<p>
	هكذا تُسند كلّ خاصيات <code>options</code> (عدا <code>extra</code> الناقصة يسار عبارة الإسناد) إلى المتغيرات المقابلة لها:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="33731" href="https://academy.hsoub.com/uploads/monthly_2020_02/destructuring-complex.png.982dd9420d41da46234d4c5e3be5236c.png" rel=""><img alt="destructuring-complex.png" class="ipsImage ipsImage_thumbnailed" data-fileid="33731" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/destructuring-complex.png.982dd9420d41da46234d4c5e3be5236c.png"></a>
</p>

<p>
	وفي النهاية يكون لدينا المتغيّرات <code>width</code> و<code>height</code> و<code>item1</code> و<code>item2</code> و<code>title</code> من تلك القيمة المبدئية. لاحظ ألّا وجود لمتغيّرات تنسخ <code>size</code> و<code>items</code> إذ ما نريد هو محتواها لا هي.
</p>

<h2>
	مُعاملات الدوال الذكية
</h2>

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

<p>
	هكذا تصنع تلك الدالة بالأسلوب الخطأ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_59" style="">
<span class="kwd">function</span><span class="pln"> showMenu</span><span class="pun">(</span><span class="pln">title </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Untitled"</span><span class="pun">,</span><span class="pln"> width </span><span class="pun">=</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> height </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> items </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	نستدعيها هكذا؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_61" style="">
<span class="com">// نضع ‫undefined لو كانت القيم المبدئية تقوم بالغرض</span><span class="pln">
showMenu</span><span class="pun">(</span><span class="str">"My Menu"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Item1"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Item2"</span><span class="pun">])</span></pre>

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

<p>
	التفكيك لنا بالمرصاد… أعني للعون! فيمكننا تمرير المُعاملات بصيغة كائن، وستُفكّكها الدالة حالًا في متغيرات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_63" style="">
<span class="com">// نمرّر كائنًا إلى الدالة</span><span class="pln">
let options </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"My menu"</span><span class="pun">,</span><span class="pln">
  items</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Item1"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Item2"</span><span class="pun">]</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// ‫...ومباشرة تفكّها وتضعها في متغيرات</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> showMenu</span><span class="pun">({</span><span class="pln">title </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Untitled"</span><span class="pun">,</span><span class="pln"> width </span><span class="pun">=</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> height </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> items </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]})</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  
  </span><span class="com">// ‫title, items – هذه من options</span><span class="pln">
  </span><span class="com">// ‫width, height – نستعمل القيم المبدئية</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">title</span><span class="pun">}</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">width</span><span class="pun">}</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">height</span><span class="pun">}`</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// My Menu 200 100</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> items </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Item1, Item2</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

showMenu</span><span class="pun">(</span><span class="pln">options</span><span class="pun">);</span></pre>

<p>
	يمكننا أيضًا استعمال التفكيك الأكثر تعقيدًا (مع الكائنات المتداخلة وتغيير الأسماء بالنقطتين الرأسيتين):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_65" style="">
<span class="pln">let options </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"My menu"</span><span class="pun">,</span><span class="pln">
  items</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Item1"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Item2"</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"> showMenu</span><span class="pun">({</span><span class="pln">
  title </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Untitled"</span><span class="pun">,</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> w </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln">  </span><span class="com">// نضع ‫width في w</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> h </span><span class="pun">=</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span class="com">// ‫ونضع height في h</span><span class="pln">
  items</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">item1</span><span class="pun">,</span><span class="pln"> item2</span><span class="pun">]</span><span class="pln"> 
  </span><span class="com">// ‫أوّل عنصر في items يصير item1، وثاني عنصر يصير item2</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="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">title</span><span class="pun">}</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">w</span><span class="pun">}</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">h</span><span class="pun">}`</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// My Menu 100 200</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> item1 </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Item1</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> item2 </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Item2</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

showMenu</span><span class="pun">(</span><span class="pln">options</span><span class="pun">);</span></pre>

<p>
	صياغة الدالة الكاملة تتطابق مع صياغة الإسناد بالتفكيك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_67" style="">
<span class="kwd">function</span><span class="pun">({</span><span class="pln">
  incomingProperty</span><span class="pun">:</span><span class="pln"> varName </span><span class="pun">=</span><span class="pln"> defaultValue
  </span><span class="pun">...</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وحينها متى ما تمرّر كائن على أساس أنّه مُعامل، نضع الخاصية <code>incomingProperty</code> في المتغير <code>varName</code> وقيمته المبدئية هي <code>defaultValue</code>.
</p>

<p>
	لاحظ بأنّ هذا النوع من التفكيك ينتظر مُعاملًا واحدًا على الأقل في الدالة <code>showMenu()‎</code>. لو أردنا أن تكون كلّ القيم كما هي مبدئيًا، فعلينا تقديم كائن فارغ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_69" style="">
<span class="pln">showMenu</span><span class="pun">({});</span><span class="pln"> </span><span class="com">// هكذا، كل القيم كما هي مبدئيًا</span><span class="pln">

showMenu</span><span class="pun">();</span><span class="pln"> </span><span class="com">// هذا سيصرخ علينا بخطأ</span></pre>

<p>
	يمكننا إصلاح هذه المشكلة بتحديد <code>{}</code> قيمةً مبدئيةً لكامل الكائن الذي يحوي المُعاملات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_71" style="">
<span class="kwd">function</span><span class="pln"> showMenu</span><span class="pun">({</span><span class="pln"> title </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Menu"</span><span class="pun">,</span><span class="pln"> width </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> height </span><span class="pun">=</span><span class="pln"> </span><span class="lit">200</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">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">title</span><span class="pun">}</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">width</span><span class="pun">}</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">height</span><span class="pun">}`</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

showMenu</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Menu 100 200</span></pre>

<h2>
	ملخص
</h2>

<ul>
<li>
		<p>
			يتيح الإسناد بالتفكيك ربط الكائن أو المصفوفة مع متغيرات عديدة أخرى، وآنيًا.
		</p>
	</li>
	<li>
		<p>
			صياغة الكائن الكاملة هي:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_73" style="">
<span class="pln">let </span><span class="pun">{</span><span class="pln">prop </span><span class="pun">:</span><span class="pln"> varName </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">default</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">rest</span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> object</span></pre>

		<p>
			ويعني هذا بأنّ الخاصية <code>prop</code> تصير في المتغيّر <code>varName</code>، وفي حال لم توجد هذه الخاصية فستُستعمل القيمة المبدئية <code>default</code>.
		</p>

		<p>
			تُنسح حاصيات الكائنات التي لا ترتبط إلى الكائن <code>rest</code>.
		</p>
	</li>
	<li>
		<p>
			صياغة المصفوفة الكاملة هي:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_79" style="">
<span class="pln">let </span><span class="pun">[</span><span class="pln">item1 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">default</span><span class="pun">,</span><span class="pln"> item2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">rest</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> array</span></pre>

		<p>
			يصير أوّل عنصر في <code>item1</code> وثاني عنصر في <code>item2</code> وباقي المصفوفة يصير باقيًا في <code>rest</code>.
		</p>
	</li>
	<li>
		<p>
			يمكن أيضًا استخراج البيانات من المصفوفات/الكائنات المتداخلة، ويلزم أن تتطابق بنية على يسار الإسناد تلك على يمينه.
		</p>
	</li>
</ul>
<h2>
	تمارين
</h2>

<h3>
	الإسناد بالتفكيك
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	لدينا هذا الكائن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_81" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  years</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	اكتب إسنادًا بالتفكيك يقرأ:
</p>

<ul>
<li>
		خاصية <code>name</code> ويضعها في المتغير <code>name</code>.
	</li>
	<li>
		خاصية <code>years</code> ويضعها في المتغير <code>age</code>.
	</li>
	<li>
		خاصية <code>isAdmin</code> ويضعها في المتغير <code>isAdmin</code> (تكون false لو لم تكن موجودة)
	</li>
</ul>
<p>
	إليك مثالًا بالقيم بعد إجراء الإسناد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_83" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln"> years</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

</span><span class="com">// ض‫ع شيفرتك على الجانب الأيسر:</span><span class="pln">
</span><span class="com">// ... = user</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> name </span><span class="pun">);</span><span class="pln"> </span><span class="com">// John</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> age </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 30</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> isAdmin </span><span class="pun">);</span><span class="pln"> </span><span class="com">// false</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_85" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  years</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let </span><span class="pun">{</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> years</span><span class="pun">:</span><span class="pln"> age</span><span class="pun">,</span><span class="pln"> isAdmin </span><span class="pun">=</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"> user</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> name </span><span class="pun">);</span><span class="pln"> </span><span class="com">// John</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> age </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 30</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> isAdmin </span><span class="pun">);</span><span class="pln"> </span><span class="com">// false</span></pre>
</div>

<h2>
	أكبر راتب
</h2>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	إليك كائن الرواتب <code>salaries</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_87" style="">
<span class="pln">let salaries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="str">"John"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Pete"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">300</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Mary"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">250</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	اكتب دالة <code>topSalary(salaries)</code> تُعيد اسم الشخص الأكثر ثراءً وراتبًا.
</p>

<ul>
<li>
		لو كان <code>salaries</code> فارغًا فيجب أن تُعيد <code>null</code>.
	</li>
	<li>
		لو كان هناك أكثر من شخص متساوي الراتب، فتُعيد أيًا منهم.
	</li>
</ul>
<p>
	ملاحظة: استعمل <code>Object.entries</code> والإسناد بالتفكيك للمرور على أزواج ”مفاتيح/قيم“.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7141_89" style="">
<span class="kwd">function</span><span class="pln"> topSalary</span><span class="pun">(</span><span class="pln">salaries</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  let max </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  let maxName </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">for</span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> salary</span><span class="pun">]</span><span class="pln"> of </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">entries</span><span class="pun">(</span><span class="pln">salaries</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">max </span><span class="pun">&lt;</span><span class="pln"> salary</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"> salary</span><span class="pun">;</span><span class="pln">
      maxName </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">return</span><span class="pln"> maxName</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/destructuring-assignment" rel="external nofollow">Destructuring assignment</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%86%D9%88%D8%B9-date-%D8%AA%D9%85%D8%AB%D9%8A%D9%84-%D8%A7%D9%84%D8%AA%D8%A7%D8%B1%D9%8A%D8%AE-%D9%88%D8%A7%D9%84%D9%88%D9%82%D8%AA-r825/" rel="">النوع Date: تمثيل التاريخ والوقت</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%81%D8%A7%D8%AA%D9%8A%D8%AD-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D9%88%D9%82%D9%8A%D9%85%D9%87%D8%A7-%D9%88%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA%D9%87%D8%A7-r823/" rel="">مفاتيح الكائنات وقيمها ومدخلاتها</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">824</guid><pubDate>Sun, 23 Feb 2020 11:45:32 +0000</pubDate></item><item><title>&#x645;&#x641;&#x627;&#x62A;&#x64A;&#x62D; &#x627;&#x644;&#x643;&#x627;&#x626;&#x646;&#x627;&#x62A; &#x648;&#x642;&#x64A;&#x645;&#x647;&#x627; &#x648;&#x645;&#x62F;&#x62E;&#x644;&#x627;&#x62A;&#x647;&#x627; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D9%81%D8%A7%D8%AA%D9%8A%D8%AD-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D9%88%D9%82%D9%8A%D9%85%D9%87%D8%A7-%D9%88%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA%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-r823/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/40.jpg.7518ab18ca5c4ebb5f2a1197af89a9ca.jpg" /></p>

<p>
	﻿لنأخذ راحة صغيرة بعيدًا عن بنى البيانات ولنتحدّث عن طريقة المرور على عناصرها.
</p>

<p>
	رأينا في الفصل السابق التوابِع <code>map.keys()‎</code> و<code>map.values()‎</code> و<code>map.entries()‎</code>. هذه التوابِع عامّة وقد اتّفق معشر المطوّرين على استعمالها عند التعامل مع بنى البيانات. ولو أنشأنا بنية بيانات من الصفر بيدنا، فعلينا توفير "تنفيذ" تلك التوابِع أيضًا. هي أساسًا مدعومة لكلّ من:
</p>

<ul>
<li>
		الخرائط <code>Map</code>
	</li>
	<li>
		الأطقم <code>Set</code>
	</li>
	<li>
		المصفوفات <code>Array</code>
	</li>
</ul>
<p>
	كما وتدعم الكائنات العادية توابِع كتلك التوابِع باختلاف بسيط في صياغتها.
</p>

<h2>
	التوابِع keys وvalues وentries
</h2>

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

<ul>
<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/keys" rel="external">Object.keys(obj)</a><code>‎</code> -- يُعيد مصفوفة من المفاتيح.
	</li>
	<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/values" rel="external">Object.values(obj)</a><code>‎</code> -- يُعيد مصفوفة من القيم.
	</li>
	<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/entries" rel="external">Object.entries(obj)</a><code>‎</code> -- يُعيد مصفوفة من أزواج <code>[key, value]</code>.
	</li>
</ul>
<p>
	لاحظ رجاءً الفروق بينها وبين الخارطة مثلًا:
</p>

<table>
<thead><tr>
<th>
				 
			</th>
			<th>
				الخارطة
			</th>
			<th>
				الكائن
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				صياغة الاستدعاء
			</td>
			<td>
				<code>map.keys()</code>
			</td>
			<td>
				<code>Object.keys(obj)‎</code> لكن ليس <code>obj.keys()‎</code>
			</td>
		</tr>
<tr>
<td>
				قيمة الإعادة
			</td>
			<td>
				مُكرَّر
			</td>
			<td>
				مصفوفة ”حقيقية“
			</td>
		</tr>
</tbody>
</table>
<p>
	أوّل فرق واضح جليّ: علينا استدعاء <code style="font-size: 16px;">Object.keys(obj)‎</code> لا <code style="font-size: 16px;">obj.keys()‎</code>. ولكن لماذا؟ السبب الأساس هو مرونة الاستعمال. لا تنسَ بأنّ الكائنات هي أساس كلّ بنية بيانات معقّدة في جافاسكربت. يحدث بأنّ لدينا كائن طوّرناه ليحمل بيانات <code style="font-size: 16px;">data</code> محدّدة، وفيه التابِع <code style="font-size: 16px;">data.values()‎</code>، ولكنّا نريد أيضًا استدعاء <code style="font-size: 16px;">Object.values(data)‎</code> عليه.
</p>

<p>
	الفرق الثاني هو أنّ التوابِع <code>Object.*</code> تُعيد كائنات مصفوفات ”فعلية“ لا مُتعدَّدات فقط. يعزو ذلك لأسباب تاريخية بحتة. خُذ هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9928_7" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
</span><span class="pun">};</span></pre>

<ul>
<li>
		<code>Object.keys(user) = ["name", "age"]‎</code>
	</li>
	<li>
		<code>Object.values(user) = ["John", 30]‎</code>
	</li>
	<li>
		<code>Object.entries(user) = [ ["name","John"], ["age",30] ]‎</code>
	</li>
</ul>
<p>
	وهذا مثال آخر عن كيف نستعمل <code>Object.values</code> للمرور على قيم الخاصيات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9928_9" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// نمرّ على القيم</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let value of </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">values</span><span class="pun">(</span><span class="pln">user</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫John ثمّ 30</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<strong>تتجاهل هذه التوابِع الخاصيات الرمزية</strong> كما تتجاهل حلقة <code>for..in</code> الخاصيات التي تستعمل <code>Symbol(...)‎</code> مفاتيح لها، فهذه التوابِع أعلاه تتجاهلها أيضًا
</p>

<p>
	غالبًا يكون هذا ما نريد، ولكن لو أردت المفاتيح الرمزية أيضًا، فعليك استعمال التابِع المنفصل <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertySymbols" rel="external nofollow">Object.getOwnPropertySymbols</a> إذ يُعيد مصفوفة بالمفاتيح الرمزية فقط. هناك أيضًا التابِع <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/ownKeys" rel="external nofollow">Reflect.ownKeys(obj)</a> إذ يُعيد المفاتيح <em>كلها</em>.
</p>

<h2>
	تعديل محتوى الكائنات
</h2>

<p>
	ليس للكائنات تلك التوابِع المفيدة المُتاحة للعناصر (مثل <code>map</code> و<code>filter</code> وغيرها). لو أردنا تطبيق هذه التوابِع على الكائنات فيجب أوّلًا استعمال <code>Object.entries</code> وبعدها <code>Object.fromEntries</code>:
</p>

<ol>
<li>
		استعمل <code>Object.entries(obj)‎</code> لتأخذ مصفوفة لها أزواج ”مفتاح/قيمة“ من الكائن <code>obj</code>.
	</li>
	<li>
		استعمل توابِع المصفوفات على تلك المصفوفة (مثلًا <code>map</code>).
	</li>
	<li>
		استعمل <code>Object.fromEntries(array)‎</code> على المصفوفة الناتج لتُحوّلها ثانيةً إلى كائن.
	</li>
</ol>
<p>
	إليك مثالًا لدينا كائنًا فيه تسعير البضائع، ونريد مضاعفتها (إذ ارتفع الدولار):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9928_11" style="">
<span class="pln">let prices </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  banana</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  orange</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
  meat</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let doublePrices </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">fromEntries</span><span class="pun">(</span><span class="pln">
  </span><span class="com">// ‫نحوّله إلى مصفوفة، ثمّ نستعمل الطقم، ثمّ يُعيد إلينا fromEntries الكائن المطلوب</span><span class="pln">
  </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">entries</span><span class="pun">(</span><span class="pln">prices</span><span class="pun">).</span><span class="pln">map</span><span class="pun">(([</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">])</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> value </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">])</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">doublePrices</span><span class="pun">.</span><span class="pln">meat</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 8</span></pre>

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

<h2>
	تمارين
</h2>

<h3>
	مجموع الخاصيات
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	أمامك كائن <code>salaries</code> وفيه بعض الرواتب. اكتب دالة <code>sumSalaries(salaries)</code> تُعيد مجموع كلّ الرواتب، باستعمال <code>Object.values</code> وحلقة <code>for..of</code>. لو كان الكائن فارغًا فيجب أن يكون الناتج صفرًا <code>0</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9928_13" style="">
<span class="pln">let salaries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="str">"John"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Pete"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">300</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Mary"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">250</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> sumSalaries</span><span class="pun">(</span><span class="pln">salaries</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 650</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9928_15" style="">
<span class="kwd">function</span><span class="pln"> sumSalaries</span><span class="pun">(</span><span class="pln">salaries</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  let sum </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">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let salary of </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">values</span><span class="pun">(</span><span class="pln">salaries</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sum </span><span class="pun">+=</span><span class="pln"> salary</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"> sum</span><span class="pun">;</span><span class="pln"> </span><span class="com">// 650</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let salaries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="str">"John"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Pete"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">300</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Mary"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">250</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> sumSalaries</span><span class="pun">(</span><span class="pln">salaries</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 650</span></pre>

	<p>
		أو يمكننا (لو أردنا) معرفة المجموع باستعمال <code>Object.values</code> والتابِع <code>reduce</code>:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9928_17" style="">
<span class="com">// ‫يمرّ reduce على مصفوفة من الرواتب،</span><span class="pln">
</span><span class="com">// ويجمعها مع بعضها ويُعيد الناتج</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> sumSalaries</span><span class="pun">(</span><span class="pln">salaries</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">Object</span><span class="pun">.</span><span class="pln">values</span><span class="pun">(</span><span class="pln">salaries</span><span class="pun">).</span><span class="pln">reduce</span><span class="pun">((</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</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">// 650</span><span class="pln">
</span><span class="pun">}</span></pre>
</div>

<h3>
	عدد الخاصيات
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	اكتب دالة باسم <code>count(obj)‎</code> تُعيد عدد الخاصيات داخل الكائن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9928_19" style="">
<span class="pln">let user </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">'John'</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> count</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span></pre>

<p>
	حاوِل أن تكون الشيفرة بأصغر ما أمكن.
</p>

<p>
	ملاحظة: أهمِل الخاصيات الرمزية وعُدّ فقط تلك ”العادية“.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9928_21" style="">
<span class="kwd">function</span><span class="pln"> count</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">return</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">).</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/keys-values-entries" rel="external nofollow">Object.keys, values, entries</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
}

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A5%D8%B3%D9%86%D8%A7%D8%AF-%D8%A8%D8%A7%D9%84%D8%AA%D9%81%D9%83%D9%8A%D9%83-destructuring-assignment-r824/" rel="">الإسناد بالتفكيك (Destructuring assignment)</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%86%D9%88%D8%B9-weakmap-%D9%88%D8%A7%D9%84%D9%86%D9%88%D8%B9-weakset-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-%D9%88%D8%A7%D9%84%D8%A3%D8%B7%D9%82%D9%85-%D8%B6%D8%B9%D9%8A%D9%81%D8%A9-%D8%A7%D9%84%D8%A5%D8%B4%D8%A7%D8%B1%D8%A9-r822/" rel="">النوع WeakMap والنوع WeakSet: الخرائط والأطقم ضعيفة الإشارة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">823</guid><pubDate>Sun, 23 Feb 2020 11:45:35 +0000</pubDate></item><item><title>&#x627;&#x644;&#x646;&#x648;&#x639; WeakMap &#x648;&#x627;&#x644;&#x646;&#x648;&#x639; WeakSet: &#x627;&#x644;&#x62E;&#x631;&#x627;&#x626;&#x637; &#x648;&#x627;&#x644;&#x623;&#x637;&#x642;&#x645; &#x636;&#x639;&#x64A;&#x641;&#x629; &#x627;&#x644;&#x625;&#x634;&#x627;&#x631;&#x629;  &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%86%D9%88%D8%B9-weakmap-%D9%88%D8%A7%D9%84%D9%86%D9%88%D8%B9-weakset-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-%D9%88%D8%A7%D9%84%D8%A3%D8%B7%D9%82%D9%85-%D8%B6%D8%B9%D9%8A%D9%81%D8%A9-%D8%A7%D9%84%D8%A5%D8%B4%D8%A7%D8%B1%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r822/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/39.jpg.f2a96e642135fdd729f4187758391587.jpg" /></p>

<p>
	كما عرفنا من فصل «كنس المهملات»، فمُحرّك جافاسكربت يخُزّن القيمة في الذاكرة طالما يمكن أن يصل لها شيء (أي يمكن استعمالها لاحقًا). هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_7" style="">
<span class="pln">let john </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">"John"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

</span><span class="com">// ‫يمكننا الوصول إلى الكائن، فـ john هو الإشارة إليه</span><span class="pln">

</span><span class="com">// عوّض تلك الإِشارة</span><span class="pln">
john </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

</span><span class="com">// سيُزال الكائن من الذاكرة</span></pre>

<p>
	عادةً ما تكون خاصيات الكائن أو عناصر المصفوفة أو أية بنية بيانات أخرى - عادةً ما تُعدّ "مُتاحة لباقي الشيفرة" ويُبقيها المحرّك في الذاكرة طالما بنية البيانات نفسها في الذاكرة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_9" style="">
<span class="pln">let john </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">"John"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

let array </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> john </span><span class="pun">];</span><span class="pln">

john </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"> </span><span class="com">// عوّض الإشارة</span><span class="pln">

</span><span class="com">// ‫الكائن john مخزّن داخل مصفوفة ولن يُكنس باعتباره مهملات</span><span class="pln">
</span><span class="com">// ‫إذ يمكننا أخذه بهذه: array[0]‎</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_11" style="">
<span class="pln">let john </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">"John"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

let map </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">();</span><span class="pln">
map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">john</span><span class="pun">,</span><span class="pln"> </span><span class="str">"..."</span><span class="pun">);</span><span class="pln">

john </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"> </span><span class="com">// عوّض الإشارة</span><span class="pln">

</span><span class="com">// ‫الكائن john مخزّن داخل خارطة</span><span class="pln">
</span><span class="com">// ‫ويمكننا أخذه بهذه: map.keys()‎</span></pre>

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

<h2>
	WeakMap
</h2>

<p>
	أولى اختلافات الخارطة ضعيفة الإشارة <code>WeakMap</code> عن تلك العادية <code>Map</code> هي أنّها تُلزم مفاتيحها بأن تكون كائنات لا أنواع أولية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_13" style="">
<span class="pln">let weakMap </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">WeakMap</span><span class="pun">();</span><span class="pln">

let obj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln">

weakMap</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">,</span><span class="pln"> </span><span class="str">"ok"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// لا مشاكل (المفتاح كائن)</span><span class="pln">

</span><span class="com">// لا يمكن استعمال السلسلة النصية مفتاحًا</span><span class="pln">
weakMap</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"test"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Whoops"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫خطأ، لأنّ ”test“ ليس كائنًا</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_15" style="">
<span class="pln">let john </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">"John"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

let weakMap </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">WeakMap</span><span class="pun">();</span><span class="pln">
weakMap</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">john</span><span class="pun">,</span><span class="pln"> </span><span class="str">"..."</span><span class="pun">);</span><span class="pln">

john </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"> </span><span class="com">// عوّض الإشارة</span><span class="pln">

</span><span class="com">// ‫أُزيل الكائن john من الذاكرة!</span></pre>

<p>
	وازِن هذه الشيفرة بشيفرة الخارطة <code>Map</code> أعلاه. الآن حتى لو لم يكن <code>john</code> موجودًا إلا مفتاحًا لِـ <code>WeakMap</code>، فسيُحذف تلقائيًا من الخارطة (ومن الذاكرة).
</p>

<p>
	لا تدعم الخارطة ضعيفة الإشارة <code>WeakMap</code> التكرار (iteration) ولا التوابِع <code>keys()‎</code> أو <code>values()‎</code> أو <code>entries()‎</code>، ولهذا لا نقدر على أخذ كلّ المفاتيح أو القيم التي فيها. بل أنّ للخارطة <code>WeakMap</code> التوابِع الآتية:
</p>

<ul>
<li>
		<code>weakMap.get(key)‎</code>
	</li>
	<li>
		<code>weakMap.set(key, value)‎</code>
	</li>
	<li>
		<code>weakMap.delete(key)‎</code>
	</li>
	<li>
		<code>weakMap.has(key)‎</code>
	</li>
</ul>
<p>
	تفكّر بسبب وجود هذا التقييد؟ الجواب هو: أسباب تقنية. عُدّ الكائن الآن قد فقد كلّ إشارة له (مثلما حصل مع الكائن <code>john</code> في الشيفرة أعلاه)، بهذا ستُكنس مهملاته تلقائيًا، ولكن… <em>وقت حدوث هذا الكنس</em> غير موضّح تقنيًا. الواقع أنّ محرّك جافاسكربت يُحدّد ذلك: هو يُحدّد متى يمسح الذاكرة، الآن حالًا أو بعد قليل حتّى تحدث عمليات حذف أخرى. لذا فعدد العناصر الحالي داخل <code>WeakMap</code> غير معلوم تقنيًا، ربما يكون المحرّك حذفها كلها أو لم يحذفها، أو حذف بعضها، لا نعلم. لهذا السبب لا تدعم اللغة التوابِع التي تحاول الوصول إلى كلّ القيم والعناصر.
</p>

<p>
	الآن بعدما عرفناها، في أيّ حالات نستعمل هذه البنية من البيانات؟
</p>

<h2>
	استعمالاتها: بيانات إضافية
</h2>

<p>
	المجال الرئيسي لتطبيقات <code>WeakMap</code> هي <em>تخزين البيانات الإضافية</em>.
</p>

<p>
	لو كنّا نتعامل مع كائن ”ينتمي“ إلى شيفرة أخرى (وحتّى مكتبة من طرف ثالث) وأردنا تخزين بيانات معيّنة لترتبط بها، وهذه البيانات لا تكون موجودة إلا لو كان الكائن موجودًا، فَـ <code>WeakMap</code> هي ما نريد تمامًا: نضع البيانات في خارطة بإشارة ضعيفة <code>WeakMap</code> (مستعملين الكائن مفتاحًا لها). متى ما كُنس الكائن باعتباره مهملات، ستختفي تلك البيانات معه أيضًا.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_17" style="">
<span class="pln">weakMap</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">john</span><span class="pun">,</span><span class="pln"> </span><span class="str">"secret documents"</span><span class="pun">);</span><span class="pln">
</span><span class="com">// ‫إن مات john فستُدمّر تلك المستندات فائقة السرية تلقائيًا</span></pre>

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

<p>
	إليك مثالًا آخر عن دالة عَدّ باستعمال <code>Map</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_19" style="">
<span class="com">// ? visitsCount.js</span><span class="pln">
let visitsCountMap </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">();</span><span class="pln"> </span><span class="com">// خارطة: المستخدم =&gt; عدد زياراته</span><span class="pln">

</span><span class="com">// تزيد عدد الزيارات</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> countUser</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let count </span><span class="pun">=</span><span class="pln"> visitsCountMap</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</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">
  visitsCountMap</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</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">
</span><span class="pun">}</span></pre>

<p>
	وهذا الجزء الثاني من الشيفرة (يمكن أن يستعمل هذا الملف ذاك):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_21" style="">
<span class="com">// ? main.js</span><span class="pln">
let john </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">"John"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

countUser</span><span class="pun">(</span><span class="pln">john</span><span class="pun">);</span><span class="pln"> </span><span class="com">// عُدّ الزوّار</span><span class="pln">
countUser</span><span class="pun">(</span><span class="pln">john</span><span class="pun">);</span><span class="pln">

</span><span class="com">// ‫بعدها يغادر john الحفلة</span><span class="pln">
john </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span></pre>

<p>
	هكذا ”يُفترض“ أن يُكنس الكائن <code>john</code> باعتباره مهملات، لكنّه سيبقى في الذاكرة إذ تستعمله الخارطة <code>visitsCountMap</code> مفتاحًا فيها.
</p>

<p>
	علينا مسح <code>visitsCountMap</code> حين نُزيل المستخدمين وإلا فسيزيد حجمها في الذاكرة إلى آباد الآبدين. لو كانت بنية البرمجية معقّدة، فستكون عملية المسح هذه مرهقة جدًا وغير عملية. لهذا يمكننا تجنّب التعب واستعمال <code>WeakMap</code> بدل العادية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_23" style="">
<span class="com">// ? visitsCount.js</span><span class="pln">
let visitsCountMap </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">WeakMap</span><span class="pun">();</span><span class="pln"> </span><span class="com">// خارطة بإشارة ضعيفة: المستخدم =&gt; عدد زياراته</span><span class="pln">

</span><span class="com">// تزيد عدد الزيارات</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> countUser</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let count </span><span class="pun">=</span><span class="pln"> visitsCountMap</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</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">
  visitsCountMap</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</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">
</span><span class="pun">}</span></pre>

<p>
	هكذا لا نمسح <code>visitsCountMap</code> يدويًا بل نترك للمحرّك القرار: لو لم يكن هناك ما يُشير إلى الكائن <code>john</code> عدا مفتاح <code>WeakMap</code>، سيحرّره من الذاكرة مع المعلومات التي في ذلك المفتاح داخل الخارطة ضعيفة الإشارة <code>WeakMap</code>.
</p>

<h2>
	استعمالاتها: الخبيئة
</h2>

<p>
	يكثُر أيضًا استعمال الخرائط للخبيئة، أي حين علينا تذكّر ناتج الدالة (تخبئته ”cached“) كي يستعمل أيّ استدعاء لاحِق على هذا العنصر تلك الخبيئة.
</p>

<p>
	يمكن أن نستعمل الخارطة <code>Map</code> لتخزين النتائج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_25" style="">
<span class="com">// ? cache.js</span><span class="pln">
let cache </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</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"> process</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">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">cache</span><span class="pun">.</span><span class="pln">has</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">
    let result </span><span class="pun">=</span><span class="pln"> </span><span class="com">/* حسابات الكائن هذا */</span><span class="pln"> obj</span><span class="pun">;</span><span class="pln">

    cache</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">obj</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">return</span><span class="pln"> cache</span><span class="pun">.</span><span class="kwd">get</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="com">// الآن نستعمل ‫process()‎ في ملف آخر:</span><span class="pln">

</span><span class="com">// ? main.js</span><span class="pln">
let obj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="com">/* فلنفترض وجود هذا الكائن*/</span><span class="pun">};</span><span class="pln">

let result1 </span><span class="pun">=</span><span class="pln"> process</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">);</span><span class="pln"> </span><span class="com">// حسبنا القيمة</span><span class="pln">

</span><span class="com">// ‫...بعدها، في مكان آخر من الشيفرة...</span><span class="pln">
let result2 </span><span class="pun">=</span><span class="pln"> process</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">);</span><span class="pln"> </span><span class="com">// تُأخذ النتيجة تلك من الخبيئة</span><span class="pln">

</span><span class="com">// ‫...بعدها، لو لم نرد الكائن بعد الآن:</span><span class="pln">
obj </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">cache</span><span class="pun">.</span><span class="pln">size</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1 (لاا! ما زال الكائن في الخبيئة ويستهلك الذاكرة)</span></pre>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_27" style="">
<span class="com">// ? cache.js</span><span class="pln">
</span><span class="pun">*!*</span><span class="pln">
let cache </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">WeakMap</span><span class="pun">();</span><span class="pln">
</span><span class="pun">*/!*</span><span class="pln">

</span><span class="com">// نحسب النتيجة ونتذكرها</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> process</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">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">cache</span><span class="pun">.</span><span class="pln">has</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">
    let result </span><span class="pun">=</span><span class="pln"> </span><span class="com">/* حسابات الكائن هذا */</span><span class="pln"> obj</span><span class="pun">;</span><span class="pln">

    cache</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">obj</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">return</span><span class="pln"> cache</span><span class="pun">.</span><span class="kwd">get</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="com">// ? main.js</span><span class="pln">
let obj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="com">/* كائن من الكائنات */</span><span class="pun">};</span><span class="pln">

let result1 </span><span class="pun">=</span><span class="pln"> process</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">);</span><span class="pln">
let result2 </span><span class="pun">=</span><span class="pln"> process</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">);</span><span class="pln">

</span><span class="com">// ‫...بعدها، لو لم نرد الكائن بعد الآن:</span><span class="pln">
obj </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span></pre>

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

<h2>
	WeakSet
</h2>

<p>
	حتّى الأطقم ضعيفة الإشارة <code>WeakSet</code> تسلك ذات السلوك:
</p>

<ul>
<li>
		تشبه الأطقم العادية <code>Set</code> ولكن لا يمكننا إلّا إضافة الكائنات إلى <code>WeakSet</code> (وليس الأنواع الأولية).
	</li>
	<li>
		يبقى الكائن موجودًا في الطقم طالما هناك ما يصل إليه.
	</li>
	<li>
		ويدعم -كما تدعم <code>Set</code>- التوابِع <code>add</code> و<code>has</code> و<code>delete</code>، ولكن لا تدعم <code>size</code> أو <code>keys()‎</code> أو التعداد.
	</li>
</ul>
<p>
	هي الأخرى تخدمنا نحن المطورون في تخزين البيانات الإضافية (إذ أنّ الإشارة إليها ”ضعيفة“)، ولكنها ليست لأيّ بيانات كانت، بل فقط التي تُعطي إجابة ”نعم/لا“. لو كان الكائن موجودًا داخل طقم بإشارة ضعيفة، فلا بدّ أنّه موجود لداعٍ.
</p>

<p>
	يمكننا مثلًا إضافة المستخدمين إلى طقم بإشارة ضعيفة <code>WeakSet</code> لنسجّل من زار موقعنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_29" style="">
<span class="pln">let visitedSet </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">WeakSet</span><span class="pun">();</span><span class="pln">

let john </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">"John"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let pete </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">"Pete"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let mary </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">"Mary"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

visitedSet</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">john</span><span class="pun">);</span><span class="pln"> </span><span class="com">// زارنا ‫John</span><span class="pln">
visitedSet</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pete</span><span class="pun">);</span><span class="pln"> </span><span class="com">// وبعده ‫Pete</span><span class="pln">
visitedSet</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">john</span><span class="pun">);</span><span class="pln"> </span><span class="com">// وعاد ‫John</span><span class="pln">

</span><span class="com">// ت‫حتوي visitedSet الآن على مستخدمين اثنين</span><span class="pln">

</span><span class="com">// ه‫ل زارنا John؟</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">visitedSet</span><span class="pun">.</span><span class="pln">has</span><span class="pun">(</span><span class="pln">john</span><span class="pun">));</span><span class="pln"> </span><span class="com">// true</span><span class="pln">

</span><span class="com">// ‫هل زارتنا Mary؟</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">visitedSet</span><span class="pun">.</span><span class="pln">has</span><span class="pun">(</span><span class="pln">mary</span><span class="pun">));</span><span class="pln"> </span><span class="com">// false</span><span class="pln">

john </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

</span><span class="com">// ستُنظّف ‫visitedSet تلقائيًا</span></pre>

<p>
	التقييد الأهم في هذه الأنواع <code>WeakSet</code> و<code>WeakMap</code> هي عدم موجود المُكرَّرات واستحالة أخذ محتواها كله. لربّما ترى ذلك غباءً، إلّا أنّه لا يمنع هذه الأنواع من إجراء مهامها التي صُنعت لها: مخزن "إضافي" من البيانات للكائنات المخزّنة (أو المُدارة) في مكان آخر.
</p>

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

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

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

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

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

<h2>
	تمارين
</h2>

<h3>
	تخزين رايات ”غير مقروءة“
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	لديك مصفوفة من الرسائل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_31" style="">
<span class="pln">let messages </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"How goes?"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"See you soon"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Alice"</span><span class="pun">}</span><span class="pln">
</span><span class="pun">];</span></pre>

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

<p>
	السؤال هو: أيّ بنية من بنى البيانات تستعمل لتخزّن هذه المعلومة لكلّ رسالة: ”هل قُرأت؟“. يجب أن تكون البنية التي اخترتها مناسبة لتردّ على سؤال ”هل قُرأت؟“ لكلّ كائن رسالة.
</p>

<p>
	ملاحظة: حين تُزال رسالة من مصفوفة <code>messages</code>، يجب أن تختفي من بنية البيانات لديك هي الأخرى.
</p>

<p>
	ملاحظة أخرى: يجب ألّا نُعدّل كائنات الرسائل ولا نُضيف خاصيات من عندنا إليها؛ فيمكن أن يؤدّي هذا إلى عواقب وخيمة إذ لسنا من نديرها بل أحد آخر.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		لنجرّب تخزين الرسائل المقروءة في طقم بإشارة ضعيفة <code>WeakSet</code>:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_33" style="">
<span class="pln">let messages </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"How goes?"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"See you soon"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Alice"</span><span class="pun">}</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

let readMessages </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">WeakSet</span><span class="pun">();</span><span class="pln">

</span><span class="com">// قرأ المستخدم رسالتين اثنتين</span><span class="pln">
readMessages</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">messages</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]);</span><span class="pln">
readMessages</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">messages</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]);</span><span class="pln">
</span><span class="com">// في ‫readMessages الآن عنصرين</span><span class="pln">

</span><span class="com">// ‫...هيًا نُعيد قراءة أول رسالة!</span><span class="pln">
readMessages</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">messages</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]);</span><span class="pln">
</span><span class="com">// ما زالت في ‫readMessages عنصرين فريدين</span><span class="pln">

</span><span class="com">// ‫الجواب: هل قُرئتmessage [0]‎؟</span><span class="pln">
alert</span><span class="pun">(</span><span class="str">"Read message 0: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> readMessages</span><span class="pun">.</span><span class="pln">has</span><span class="pun">(</span><span class="pln">messages</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]));</span><span class="pln"> </span><span class="com">// نعم ‫true</span><span class="pln">

messages</span><span class="pun">.</span><span class="pln">shift</span><span class="pun">();</span><span class="pln">
</span><span class="com">// الآن في ‫readMessages عنصر واحد (تقنيًا فستُنظّف الذاكرة فيما بعد)</span></pre>

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

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

	<p>
		هكذا:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_35" style="">
<span class="com">// الخاصية الرمزية معروفة في الشيفرة لدينا، فقط</span><span class="pln">
let isRead </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Symbol</span><span class="pun">(</span><span class="str">"isRead"</span><span class="pun">);</span><span class="pln">
messages</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="pln">isRead</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span></pre>

	<p>
		"لربما" الآن لن تعرف شيفرة الطرف الثالث بخاصيتنا الجديدة.
	</p>

	<p>
		صحيح أن الرموز تتيح لنا تقليل احتمال حدوث المشاكل، إلّا أنّ استعمال <code>WeakSet</code> أفضل بعين بنية البرمجية.
	</p>
</div>

<h3>
	تخزين تواريخ القراءة
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	لديك مصفوفة من الرسائل تشبه تلك في التمرين السابق، والفكرة هنا متشابهة قليلًا.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_37" style="">
<span class="pln">let messages </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"How goes?"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"See you soon"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Alice"</span><span class="pun">}</span><span class="pln">
</span><span class="pun">];</span></pre>

<p>
	السؤال: أيّ بنية بيانات تستعمل لتخزين هذه المعلومة: " متى قُرئت هذه الرسالة؟".
</p>

<p>
	كان عليك (في التمرين السابق) تخزين معلومة "نعم/لا" فقط، أمّا الآن فعليك تخزين التاريخ، ويجب أن يبقى في الذاكرة إلى أن تُكنس الرسالة على أنّها مهملات.
</p>

<p>
	ملاحظة: تُخزّن التواريخ كائنات بصنف <code>Date</code> المضمّن في اللغة، وسنتكلم عنه لاحقًا.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		يمكن أن نستعمل الخارطة ضعيفة الإشارة لتخزين التاريخ:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9740_39" style="">
<span class="pln">let messages </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"How goes?"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> </span><span class="str">"See you soon"</span><span class="pun">,</span><span class="pln"> from</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Alice"</span><span class="pun">}</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

let readMap </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">WeakMap</span><span class="pun">();</span><span class="pln">

readMap</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">messages</span><span class="pun">[</span><span class="lit">0</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">2017</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">1</span><span class="pun">));</span><span class="pln">
</span><span class="com">// سنرى أمر كائن التاريخ لاحقًا</span></pre>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/weakmap-weakset" rel="external nofollow">WeakMap and WeakSet</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%81%D8%A7%D8%AA%D9%8A%D8%AD-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D9%88%D9%82%D9%8A%D9%85%D9%87%D8%A7-%D9%88%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA%D9%87%D8%A7-r823/" rel="">مفاتيح الكائنات وقيمها ومدخلاتها</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%86%D9%88%D8%B9-map-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-%D9%88%D8%A7%D9%84%D9%86%D9%88%D8%B9-set-%D8%A7%D9%84%D8%A3%D8%B7%D9%82%D9%85-r821/" rel="">النوع Map (الخرائط) والنوع Set (الأطقم)</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">822</guid><pubDate>Sun, 23 Feb 2020 11:45:43 +0000</pubDate></item><item><title>&#x627;&#x644;&#x646;&#x648;&#x639; Map (&#x627;&#x644;&#x62E;&#x631;&#x627;&#x626;&#x637;) &#x648;&#x627;&#x644;&#x646;&#x648;&#x639; Set (&#x627;&#x644;&#x623;&#x637;&#x642;&#x645;) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%86%D9%88%D8%B9-map-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-%D9%88%D8%A7%D9%84%D9%86%D9%88%D8%B9-set-%D8%A7%D9%84%D8%A3%D8%B7%D9%82%D9%85-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r821/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/38.jpg.7ceb5187b813202846154924f9c198fa.jpg" /></p>

<p>
	﻿تعلّمنا حتّى الآن بنى البيانات المعقّدة هذه:
</p>

<ul>
<li>
		الكائنات <code>Object</code>: لتخزين التجميعات ذات المفاتيح.
	</li>
	<li>
		المصفوفات <code>Array</code>: لتخزين التجميعات المرتّبة.
	</li>
</ul>
<p>
	ولكن في الحياة الواقعية، هذا لا يكفي. ولهذا تقدّم لك اللغة نوعيين آخرين: الخارطة <code>Map</code> والطقم <code>Set</code>.
</p>

<h2>
	الخارطة <code>Map</code>
</h2>

<p>
	تُعدّ <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map" rel="external nofollow">الخارطة</a> تجميعة ذات مفاتيح من عناصر البيانات، تمامًا مثل الكائنات <code>Object</code>، مع فرق بسيط، هو أنّ الخارطة <code>Map</code> تتيح استعمال المفاتيح مهمًا كان نوعها.
</p>

<p>
	هذه توابِعها وخاصياتها:
</p>

<ul>
<li>
		<code>new Map()‎</code> -- يُنشِئ خارطة.
	</li>
	<li>
		<code>map.set(key, value)‎</code> -- يضبط القيمة حسب مفتاحها.
	</li>
	<li>
		<code>map.get(key)‎</code> -- يجلب القيمة حسب مفتاحها، و<code>undefined</code> لو لم يوجد <code>key</code> في الخارطة.
	</li>
	<li>
		<code>map.has(key)‎</code> -- يُعيد <code>true</code> لو كان <code>key</code> موجودًا، وإلا فَـ <code>false</code>.
	</li>
	<li>
		<code>map.delete(key)‎</code> -- يُزيل القيمة حسب مفتاحها.
	</li>
	<li>
		<code>map.clear()‎</code> -- يُزيل كل شيء من الخارطة.
	</li>
	<li>
		<code>map.size</code> -- يُعيد عدد العناصر الحالي.
	</li>
</ul>
<p>
	إليك المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_7" style="">
<span class="pln">let map </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">();</span><span class="pln">

map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">'1'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'str1'</span><span class="pun">);</span><span class="pln">   </span><span class="com">// المفتاح سلسلة نصية</span><span class="pln">
map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="str">'num1'</span><span class="pun">);</span><span class="pln">     </span><span class="com">// المفتاح عدد</span><span class="pln">
map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bool1'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// المفتاح قيمة منطقية</span><span class="pln">

</span><span class="com">// أتذكر كيف أنّ الكائن العادي يُحوّل المفاتيح لأي سلاسل نصية؟</span><span class="pln">
</span><span class="com">// ‫الخارطة هنا تحترم النوع، وهذان السطران مختلفان:</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> map</span><span class="pun">.</span><span class="kwd">get</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"> </span><span class="com">// 'num1'</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> map</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'1'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 'str1'</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> map</span><span class="pun">.</span><span class="pln">size </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3</span></pre>

<p>
	كما ترى، فالمفاتيح لا تُحوّل إلى سلاسل نصية (على العكس من الكائنات). يمكنك أن تضع أيّ نوع من المفاتيح تريد.
</p>

<p>
	<strong>يمكن أن تستعمل الخارطة الكائناتَ نفسها مفاتيح.</strong>
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_9" style="">
<span class="pln">let john </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">"John"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

</span><span class="com">// لنخزّن عدد زيارات كل زائر لنا</span><span class="pln">
let visitsCountMap </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">();</span><span class="pln">

</span><span class="com">// ‫كائن john هو مفتاح الخارطة</span><span class="pln">
visitsCountMap</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">john</span><span class="pun">,</span><span class="pln"> </span><span class="lit">123</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> visitsCountMap</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">john</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 123</span></pre>

<p>
	يُعدّ استعمال الكائنات على أنّها مفاتيح أحدُ أهمّ صفات <code>Map</code>. لو أردت المفاتيح سلاسل نصية، فالكائنات <code>Object</code> تكفيك وزيادة، لكن لو أردت المفاتيح كائنات، فسيخونك <code>Object</code> للأسف. لنرى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_11" style="">
<span class="pln">let john </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">"John"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

let visitsCountObj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln"> </span><span class="com">// نحاول استعمال كائن</span><span class="pln">

visitsCountObj</span><span class="pun">[</span><span class="pln">john</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">123</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫ونحاول استعمال كائن john مفتاحًا فيه</span><span class="pln">

</span><span class="com">// ‫وهذا ما وجدناه مكتوبًا!</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> visitsCountObj</span><span class="pun">[</span><span class="str">"[object Object]"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 123</span></pre>

<p>
	المتغيّر <code>visitsCountObj</code> من نوع ”كائن“، ولهذا يحوّل كلّ المفاتيح (مثل <code>john</code>) إلى سلاسل نصية. وبهذا قدّم لنا المفتاح بالسلسلة النصية <code>"[object Object]"</code>. ليس ما نريد قطعًا.
</p>

<p>
	<strong>كيف تُوازن الخارطة <code>Map</code> المفاتيح</strong>
</p>

<p>
	تستعمل <code>Map</code> الخوارزمية <a href="https://tc39.github.io/ecma262/#sec-samevaluezero" rel="external nofollow">SameValueZero</a> لتختبر تساوي المفتاح مع الآخر. تتشابه هذه الخوارزمية تقريبًا مع المساواة الصارمة <code>===</code> بفارق أنّ <code>NaN</code> تساوي <code>NaN</code> في نظرها. يعني ذلك بأنك تستطيع استعمال <code>NaN</code> كمفتاح هو الآخر.
</p>

<p>
	لا يمكن تغيير هذه الخوارزمية ولا تخصيصها.
</p>

<p>
	<strong>سِلسلة الاستدعاءات</strong> كلّما نادينا <code>map.set</code> أعاد لنا التابِع الخارطة نفسها، وبهذا يمكن أن نستدعي التابع على ناتج الاستدعاء السابق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_13" style="">
<span class="pln">map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">'1'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'str1'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="str">'num1'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bool1'</span><span class="pun">);</span></pre>

<h2>
	المرور على خارطة
</h2>

<p>
	هناك ثلاث طرائق للمرور على عناصر <code>Map</code> وتطبيق عملية عليها:
</p>

<ul>
<li>
		<code>map.keys()‎</code> -- يُعيد مُتعدَّدًا للمفاتيح،
	</li>
	<li>
		<code>map.values()‎</code> -- يُعيد مُتعدَّدًا للقيم،
	</li>
	<li>
		<code>map.entries()‎</code> -- يُعيد مُتعدَّدًا للمدخلات <code>[key, value]</code>، وهي التي تستعملها <code>for..of</code> مبدئيًا.
	</li>
</ul>
<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_15" style="">
<span class="pln">let recipeMap </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">([</span><span class="pln">
  </span><span class="pun">[</span><span class="str">'cucumber'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">500</span><span class="pun">],</span><span class="pln">
  </span><span class="pun">[</span><span class="str">'tomatoes'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">350</span><span class="pun">],</span><span class="pln">
  </span><span class="pun">[</span><span class="str">'onion'</span><span class="pun">,</span><span class="pln">    </span><span class="lit">50</span><span class="pun">]</span><span class="pln">
</span><span class="pun">]);</span><span class="pln">

</span><span class="com">// نمرّ على المفاتيح (الخضراوات)‏</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let vegetable of recipeMap</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">vegetable</span><span class="pun">);</span><span class="pln"> </span><span class="com">// cucumber, tomatoes, onion</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// نمرّ على قيم المفاتيح (عدد الخضراوات)‏</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let amount of recipeMap</span><span class="pun">.</span><span class="pln">values</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">amount</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 500, 350, 50</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// ‫نمرّ على مدخلات [key, value]</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let entry of recipeMap</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ‫مثل recipeMap.entries()‎</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">entry</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫cucumber,500 (وهكذا)</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	علاوةً على ذلك، فتملك الخارطة <code>Map</code> التابِع المضمّن فيها <code>forEach</code>، كما المصفوفات <code>Array</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_17" style="">
<span class="com">// ‫تُنفّذ الدالة على كلّ زوج (key, value)</span><span class="pln">
recipeMap</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> map</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">key</span><span class="pun">}:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">value</span><span class="pun">}`);</span><span class="pln"> </span><span class="com">// ‫cucumber: 500 إلخ إلخ</span><span class="pln">
</span><span class="pun">});</span></pre>

<h2>
	Object.entries: صنع خارطة من كائن
</h2>

<p>
	متى ما أُنشأت خارطة <code>Map</code> نستطيع تمرير مصفوفة (أو مُتعدَّدًا آخرًا) لها أزواج ”مفاتيح/قيم“ لتهيئتها، هكذا تمامًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_19" style="">
<span class="com">// ‫مصفوفة من أزواج [key, value]</span><span class="pln">
let map </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">([</span><span class="pln">
  </span><span class="pun">[</span><span class="str">'1'</span><span class="pun">,</span><span class="pln">  </span><span class="str">'str1'</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="str">'num1'</span><span class="pun">],</span><span class="pln">
  </span><span class="pun">[</span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bool1'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">]);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> map</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'1'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// str1</span></pre>

<p>
	لو كان أمامنا كائنًا عاديًا ونريد صناعة <code>Map</code> منه، فيمكننا استعمال التابِع المضمّن في اللغة <a href="https://wiki.hsoub.com/JavaScript/Object/entries" rel="external">Object.entries(obj)</a> إذ يُعيد مصفوفة مكوّنة من أزواج ”مفاتيح/قيم“ للكائن، بنفس الصيغة التي يطلبها ذاك التابِع.
</p>

<p>
	ولهذا يمكن أن نصنع خارطة من كائن بهذه الطريقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_21" style="">
<span class="pln">let obj </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">"John"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let map </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">(</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">entries</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">));</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> map</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'name'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// John</span></pre>

<p>
	نرى هنا التابِع <code>Object.entries</code> يُعيد مصفوفة بأزواج ”مفاتيح/قيم“: <code>[ ["name","John"], ["age", 30] ]</code>، وهذا ما تحتاجه الخارطة.
</p>

<h2>
	Object.fromEntries: صنع كائن من خارطة
</h2>

<p>
	رأينا كيف نصنع خارطة <code>Map</code> من كائنٍ عاديّ باستعمال <code>Object.entries(obj)‎</code>. على العكس منه فالتابع <code>Object.fromEntries</code> يأخذ خارطة فيها أزواج <code>[key, value]</code> ويصنع كائنًا منها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_25" style="">
<span class="pln">let prices </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">fromEntries</span><span class="pun">([</span><span class="pln">
  </span><span class="pun">[</span><span class="str">'banana'</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="str">'orange'</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="str">'meat'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">]</span><span class="pln">
</span><span class="pun">]);</span><span class="pln">

</span><span class="com">// prices = { banana: 1, orange: 2, meat: 4 }</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">prices</span><span class="pun">.</span><span class="pln">orange</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span></pre>

<p>
	يمكننا استعمال <code>Object.fromEntries</code> لنصنع كائنًا عاديًا من <code>Map</code>. يُفيدنا هذا مثلًا في تخزين البيانات في خارطة، بينما نريد تمريرها إلى شيفرة من طرف ثالثة تريد كائنًا عاديًا لا خارطة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_27" style="">
<span class="pln">let map </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">();</span><span class="pln">
map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">'banana'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">'orange'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">
map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">'meat'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">);</span><span class="pln">

let obj </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">fromEntries</span><span class="pun">(</span><span class="pln">map</span><span class="pun">.</span><span class="pln">entries</span><span class="pun">());</span><span class="pln"> </span><span class="com">// ن‫صنع كائنًا عاديًا (*)</span><span class="pln">

</span><span class="com">//و‫هكذا انتهينا!</span><span class="pln">
</span><span class="com">// obj = { banana: 1, orange: 2, meat: 4 }</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">orange</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span></pre>

<p>
	متى ما استدعينا <code>map.entries()‎</code> أعادت مصفوفة مؤلّفة من أزواج ”مفاتيح/قيم“ بنفس التنسيق الذي يطلبه <code>Object.fromEntries</code> تمامًا، لحسن الحظ.
</p>

<p>
	يمكننا تقصير السطر المعلّم <code>(*)</code> ذاك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_29" style="">
<span class="pln">let obj </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">fromEntries</span><span class="pun">(</span><span class="pln">map</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ب‫دون ‎.entries()‎</span></pre>

<p>
	النتيجة نفسها إذ أنّ التابِع <code>Object.fromEntries</code> يتوقّع كائنًا مُتعدَّدًا وسيطًا له، وليس مصفوفة بالضرورة. كما والتعداد القياسي للخارطة يتوقّع ذات أزواج ”مفاتيح/قيم“ التي يتوقّعها <code>map.entries()‎</code>، وهكذا نجد في يدنا كائنًا عاديًا له نفس ”مفاتيح/قيم“ الخارطة <code>map</code>.
</p>

<h2>
	الطقم <code>Set</code>
</h2>

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

<p>
	إليك توابِعه الرئيسة:
</p>

<ul>
<li>
		<code>new Set(iterable)‎</code> -- يصنع الطقم. في حال مرّرت كائن <code>iterable</code> (وهو عادةً مصفوفة)، فينسخ بياناته إلى الطقم.
	</li>
	<li>
		<code>set.add(value)‎</code> -- يُضيف قيمة إلى الطقم ويُعيده ذاته.
	</li>
	<li>
		<code>set.delete(value)‎</code> -- يُزيل القيمة ويُعيد <code>true</code> لو كانت القيمة <code>value</code> موجودة عند استدعاء التابِع، وإلّا يُعيد <code>false</code>.
	</li>
	<li>
		<code>set.has(value)‎</code> -- يُعيد <code>true</code> لو كانت القيمة موجودة في الطقم، وإلّا يُعيد <code>false</code>.
	</li>
	<li>
		<code>set.clear()‎</code> -- يُزيل كلّ شيء من الطقم.
	</li>
	<li>
		<code>set.size</code> -- خاصية عدد العناصر في الطقم.
	</li>
</ul>
<p>
	الميزة الأهمّ للأطقم هي أنّك لو استدعيت <code>set.add(value)‎</code> أكثر من مرّة وبنفس القيمة، فكأنّك استدعيتهُ مرّة واحدة. لهذا تظهر كل قيمة في الطقم مرّة واحدة لا غير.
</p>

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

<p>
	الطقم هنا هو الخيار الأمثل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_31" style="">
<span class="pln">let </span><span class="kwd">set</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Set</span><span class="pun">();</span><span class="pln">

let john </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">"John"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let pete </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">"Pete"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let mary </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">"Mary"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

</span><span class="com">// زارنا الناس، وهناك من زارنا أكثر من مرة</span><span class="pln">
</span><span class="kwd">set</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">john</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">set</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pete</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">set</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">mary</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">set</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">john</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">set</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">mary</span><span class="pun">);</span><span class="pln">

</span><span class="com">// لا يحفظ الطقم إلا القيم الفريدة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">.</span><span class="pln">size </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let user of </span><span class="kwd">set</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫John (ثمّ Pete وMary)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن عوض الأطقم استعمال مصفوفة من المستخدمين، مع نصّ يتحقّق من البيانات عند إدخالها لألّا تحدث تكرارات (باستعمال <a href="https://wiki.hsoub.com/JavaScript/Array/find" rel="external">arr.find</a>). هذا ممكن نعم، لكن الأداء سيكون أشنع بكثير فتابِع البحث <code>arr.find</code> يمرّ على <em>كامل المصفوفة</em> فيفحص كلّ عنصر فيها. الطقم <code>Set</code> أفضل بمراحل فأداؤه في فحص تفرّد العناصر مُحسَّن داخل بنية اللغة.
</p>

<h2>
	المرور على طقم
</h2>

<p>
	يمكن لنا المرور على عناصر الطقم باستعمال حلقة <code>for..of</code> أو تابِع <code>forEach</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_33" style="">
<span class="pln">let </span><span class="kwd">set</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Set</span><span class="pun">([</span><span class="str">"oranges"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"apples"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"bananas"</span><span class="pun">]);</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let value of </span><span class="kwd">set</span><span class="pun">)</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span class="pln">

</span><span class="com">// ‫نفس الأمر مع forEach:</span><span class="pln">
</span><span class="kwd">set</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> valueAgain</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">set</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	ولكن لاحظ هنا طرافة التابِع: لدالة ردّ النداء المُمرّرة إلى <code>forEach</code> ثلاث وُسطاء: قيمة <code>value</code>، و<em>ذات القيمة الأولى</em> <code>valueAgain</code>، والكائن الهدف. لاحظتَ كيف تكرّرت ذات القيمة في الوُسطاء مرّتين؟
</p>

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

<p>
	كما تدعم الأطقم نفس التوابِع التي تدعمها الخارطة للتعامل مع المُتعدَّدات:
</p>

<ul>
<li>
		<code>set.keys()‎</code> -- يُعيد كائنًا مُتعدَّدًا من القيم،
	</li>
	<li>
		<code>set.values()‎</code> -- تمامًا مثل <code>set.keys()‎</code> (موجود للتوافق مع <code>Map</code>)،
	</li>
	<li>
		<code>set.entries()‎</code> -- يُعيد كائنًا مُتعدَّدًا من المُدخلات <code>[value, value]</code> (موجود للتوافق مع <code>Map</code>).
	</li>
</ul>
<h2>
	ملخص
</h2>

<p>
	الخارطة <code>Map</code> هي تجميعة ذات مفاتيح.
</p>

<p>
	توابعها وخاصياتها:
</p>

<ul>
<li>
		<code>new Map([iterable])‎</code> -- يصنع خريطة ويضع فيها أزواج <code>[key,value]</code> داخل المُتعدَّد <code>iteratable</code> الاختياري (يمكن أن يكون مثلًا مصفوفة).
	</li>
	<li>
		<code>map.set(key, value)‎</code> -- يخزّن القيمة حسب مفتاحها.
	</li>
	<li>
		<code>map.get(key)‎</code> -- يُعيد القيمة حسب مفتاحها، ويُعيد <code>undefined</code> لو لم يكن المفتاح <code>key</code> في الخارطة.
	</li>
	<li>
		<code>map.has(key)‎</code> -- يُعيد <code>true</code> لو كان المفتاح <code>key</code> موجودًا، وإلا يُعيد <code>false</code>.
	</li>
	<li>
		<code>map.delete(key)‎</code> -- يُزيل القيمة حسب مفتاحها.
	</li>
	<li>
		<code>map.clear()‎</code> -- يُزيل كل ما في الخارطة.
	</li>
	<li>
		<code>map.size</code> -- يُعيد عدد العناصر في الخارطة الآن.
	</li>
</ul>
<p>
	اختلافاتها مع الكائنات العادية (<code>Object</code>):
</p>

<ul>
<li>
		تدعم أنواع المفاتيح المختلفة، كما والكائنات نفسها أيضًا.
	</li>
	<li>
		فيها توابِع أخرى تفيدنا، كما وخاصية <code>size</code>.
	</li>
</ul>
<p>
	الطقم <code>Set</code> هو تجميعة من القيم الفريدة.
</p>

<p>
	توابعه وخاصياته:
</p>

<ul>
<li>
		<code>new Set([iterable])‎</code> -- يصنع طقمًا ويضع فيه أزواج <code>[key, value]</code> داخل المُتعدَّد الاختياري (يمكن أن يكون مثلًا مصفوفة).
	</li>
	<li>
		<code>set.add(value)‎</code> -- يُضيف القيمة <code>value</code> (ولو كانت موجودة لا يفعل شيء) ثمّ يُعيد الطقم نفسه.
	</li>
	<li>
		<code>set.delete(value)‎</code> -- يُزيل القيمة ويُعيد <code>true</code> لو كانت موجودة عند استدعاء التابِع، وإلا يُعيد <code>false</code>.
	</li>
	<li>
		<code>set.has(value)‎</code> -- يُعيد <code>true</code> لو كانت القيمة في الطقم، وإلا يُعيد <code>false</code>.
	</li>
	<li>
		<code>set.clear()‎</code> -- يُزيل كل ما في الطقم.
	</li>
	<li>
		<code>set.size</code> -- عدد عناصر الطقم.
	</li>
</ul>
<p>
	يسري ترتيب المرور على عناصر <code>Map</code> و<code>Set</code> بترتيب إدخالها فيهما <em>دومًا</em>، ولهذا لا يمكن أن نقول بأنّها تجميعات غير مرتّبة، بل أنّا لا نقدر على إعادة ترتيب عناصرها أو الحصول عليها بفهرسها فيها.
</p>

<h2>
	تمارين
</h2>

<h3>
	ترشيح العناصر الفريدة في مصفوفة
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	عُدّ أنّ <code>arr</code> مصفوفة. أنشِئ دالة <code>unique(arr)‎</code> تُعيد مصفوفة مؤلّفة من العناصر الفريدة في <code>arr</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_35" style="">
<span class="kwd">function</span><span class="pln"> unique</span><span class="pun">(</span><span class="pln">arr</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">

let values </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">":-O"</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> unique</span><span class="pun">(</span><span class="pln">values</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hare, Krishna, :-O</span></pre>

<p>
	لاحظ أنّ السلاسل النصية استُعملت هنا، ولكن يمكن أن تكون القيم بأيّ نوع آخر.
</p>

<p>
	غُشّ من هذه: استعمل <code>Set</code> لتخزين القيم الفريدة.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_37" style="">
<span class="kwd">function</span><span class="pln"> unique</span><span class="pun">(</span><span class="pln">arr</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">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Set</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">));</span><span class="pln">
</span><span class="pun">}</span></pre>
</div>

<h3>
	ترشيح الألفاظ المقلوبة
</h3>

<p class="task__importance">
	<em>الأهمية: 4</em>
</p>

<p>
	تُسمّى الكلمات التي لها ذات الأحرف ولكن بترتيب مختلف <a href="https://ar.wikipedia.org/wiki/%D9%84%D9%81%D8%B8_%D9%85%D9%82%D9%84%D9%88%D8%A8" rel="external nofollow">ألفاظًا مقلوبة</a>، مثل هذه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_39" style="">
<span class="pln">nap </span><span class="pun">-</span><span class="pln"> pan
ear </span><span class="pun">-</span><span class="pln"> are </span><span class="pun">-</span><span class="pln"> era
cheaters </span><span class="pun">-</span><span class="pln"> hectares </span><span class="pun">-</span><span class="pln"> teachers</span></pre>

<p>
	أو العربية:
</p>

<pre class="ipsCode">
ملّ - لمّ
مسكين - سيكمن
كاتب - اكتب - كتاب
</pre>

<p>
	اكتب دالة <code>aclean(arr)‎</code> تُعيد مصفوفةً بدون هذه الألفاظ المقلوبة. هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_42" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"nap"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"teachers"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cheaters"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"PAN"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"ear"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"era"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"hectares"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> aclean</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "nap,teachers,ear" أو "PAN,cheaters,era"</span></pre>

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

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		لو أردنا البحث عن كل الألفاظ المقلوبة، سنقسم كلّ كلمة إلى حروفها ونرتّبها. متى ما رتّبناها حسب الأحرف، فستكون الألفاظ كلها متطابقة. هكذا:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_45" style="">
<span class="pln">nap</span><span class="pun">,</span><span class="pln"> pan </span><span class="pun">-&gt;</span><span class="pln"> anp
ear</span><span class="pun">,</span><span class="pln"> era</span><span class="pun">,</span><span class="pln"> are </span><span class="pun">-&gt;</span><span class="pln"> aer
cheaters</span><span class="pun">,</span><span class="pln"> hectares</span><span class="pun">,</span><span class="pln"> teachers </span><span class="pun">-&gt;</span><span class="pln"> aceehrst
</span><span class="pun">...</span></pre>

	<p>
		سنستعمل كلّ قيمة مختلفة (ولكن متطابقة بترتيب أحرفها) لتكون مفاتيح خريطة فنخزّن لفظًا واحدًا لكل مفتاح فقط:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_47" style="">
<span class="kwd">function</span><span class="pln"> aclean</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let map </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">();</span><span class="pln">

  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let word of arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// نقسم الكلمة بأحرفها، ونرّتب الأحرف ونجمعها ثانيةً</span><span class="pln">
    let sorted </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">.</span><span class="pln">toLowerCase</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">sort</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">// (*)</span><span class="pln">
    map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">sorted</span><span class="pun">,</span><span class="pln"> word</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">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">map</span><span class="pun">.</span><span class="pln">values</span><span class="pun">());</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"nap"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"teachers"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cheaters"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"PAN"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"ear"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"era"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"hectares"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> aclean</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span></pre>

	<p>
		نُنفّذ الترتيب حسب الأحرف بسلسلة استدعاءات كما في السطر <code>(*)</code>. سنقسمها على أكثر من سطر ليسهل فهمها:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_49" style="">
<span class="pln">let sorted </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="com">// PAN</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">()</span><span class="pln"> </span><span class="com">// pan</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln"> </span><span class="com">// ['p','a','n']</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">sort</span><span class="pun">()</span><span class="pln"> </span><span class="com">// ['a','n','p']</span><span class="pln">
  </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">// anp</span></pre>

	<p>
		هكذا يكون لدى الكلمتين المختلفتين <code>'PAN'</code> و<code>'nap'</code> ذات الشكل حين تُرتّب أحرفها: <code>'anp'</code>.
	</p>

	<p>
		في السطر اللاحق نُضيف الكلمة إلى الخارطة.
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_51" style="">
<span class="pln">map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">sorted</span><span class="pun">,</span><span class="pln"> word</span><span class="pun">);</span></pre>

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

	<p>
		وفي النهاية يأخذ <code>Array.from(map.values())‎</code> متُعدَّدا يمرّ على قيم الخارطة (لا نريد مفاتيحها في ناتج الدالة) فيُعيد المصفوفة نفسها.
	</p>

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

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_53" style="">
<span class="kwd">function</span><span class="pln"> aclean</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let obj </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="pln">let 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"> arr</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let sorted </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">toLowerCase</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">sort</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">
    obj</span><span class="pun">[</span><span class="pln">sorted</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> arr</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">return</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">values</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">

let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"nap"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"teachers"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cheaters"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"PAN"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"ear"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"era"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"hectares"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> aclean</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span></pre>
</div>

<h3>
	مفاتيح مُكرَّرة
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	نريد تسجيل المصفوفة الناتجة من <code>map.keys()‎</code> في متغيّر وثمّ استدعاء توابِع تخصّ المصفوفات عليها مثل <code>‎.push</code>. ولكنّ ذلك لم ينفع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_55" style="">
<span class="pln">let map </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">();</span><span class="pln">

map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"name"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">);</span><span class="pln">

let keys </span><span class="pun">=</span><span class="pln"> map</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">();</span><span class="pln">

</span><span class="com">// ‫خطأ: keys.push ليست دالة</span><span class="pln">
keys</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"more"</span><span class="pun">);</span></pre>

<p>
	لماذا؟ وكيف يمكننا إصلاح الشيفرة ليعمل <code>keys.push</code>؟
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		لأنّ التابِع <code>map.keys()‎</code> يُعيد مُتعدَّدًا لا مصفوفة. يمكننا تحويله إلى مصفوفة باستعمال <code>Array.from</code>:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6696_57" style="">
<span class="pln">let map </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">();</span><span class="pln">

map</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"name"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">);</span><span class="pln">

let keys </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">map</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">());</span><span class="pln">

keys</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"more"</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">keys</span><span class="pun">);</span><span class="pln"> </span><span class="com">// name, more</span></pre>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/map-set" rel="external nofollow">Map and Set</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%86%D9%88%D8%B9-weakmap-%D9%88%D8%A7%D9%84%D9%86%D9%88%D8%B9-weakset-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-%D9%88%D8%A7%D9%84%D8%A3%D8%B7%D9%82%D9%85-%D8%B6%D8%B9%D9%8A%D9%81%D8%A9-%D8%A7%D9%84%D8%A5%D8%B4%D8%A7%D8%B1%D8%A9-r822/" rel="">النوع WeakMap والنوع WeakSet: الخرائط والأطقم ضعيفة الإشارة</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%83%D8%B1%D9%91%D9%8E%D8%B1%D8%A9-iterables-r820/" rel="">الكائنات المكرَّرة (Iterables)</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">821</guid><pubDate>Sun, 23 Feb 2020 11:45:48 +0000</pubDate></item><item><title>&#x627;&#x644;&#x643;&#x627;&#x626;&#x646;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x643;&#x631;&#x651;&#x64E;&#x631;&#x629; (Iterables) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%83%D8%B1%D9%91%D9%8E%D8%B1%D8%A9-iterables-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r820/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/37.jpg.624097f5bcd4d50e55f95b42f6ec75a0.jpg" /></p>

<p>
	الكائنات <em>المُكرَّرة</em> (Iterables) هي مفهوم أعمّ من المصفوفات. تتيح لنا هذه الكائنات تحويل أيّ كائن إلى ”كائن يمكن تكراره“ فيمكننا استعماله في حلقة <code>for..of</code>.
</p>

<p>
	بالطبع فالمصفوفات يمكن تكرارها، ولكن هناك كائنات أخرى (مضمّنة في أصل اللغة) يمكن تكرارها أيضًا، مثل السلاسل النصية.
</p>

<p>
	لو لم يكن الكائن مصفوفة <em>تقنيًا</em>، ولكن يمكننا تمثيله على أنّه تجميعة من العناصر (النوع <code>list</code>، والنوع <code>set</code>)، فصياغة <code>for..of</code> ممتازة لنمرّ على عناصره. لذا دعنا نرى كيف يمكن توظيف هذه ”المُكرَّرات“.
</p>

<h2>
	Symbol.iterator
</h2>

<p>
	يمكن لنا أن نُدرك هذا المفهوم -مفهوم المُكرَّرات أعني- بأن نصنع واحدًا بنفسنا. لنقل أنّ لدينا كائن وهو ليس بمصفوفة بأيّ شكل، ولكن يمكن توظيفه لحلقة <code>for..of</code>. مثلًا كائن المدى هذا <code>range</code> يُمثّل مجموعة متتالية من الأعداد.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_7" style="">
<span class="pln">let range </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  from</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  to</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// ‫‏نُريد أن تعمل for..of هكذا:</span><span class="pln">
</span><span class="com">// for(let num of range) ... num=1,2,3,4,5</span></pre>

<p>
	لنُضيف خاصية التكرار إلى <code>range</code> (فتعمل بهذا <code>for..of</code>)، علينا إضافة تابِع إلى الكائن بالاسم <code>Symbol.iterator</code> (وهو رمز خاصّ في اللغة يتيح لنا هذه الميزة).
</p>

<ol>
<li>
		حين تبدأ <code>for..of</code>، تنادي ذلك التابِع مرة واحدة (أو تعرض الأخطاء المعروفة لو لم تجدها). على هذا التابِع إعادة <em>مُكرِّر/iterator</em>، أي كائنًا له التابِع <code>next</code>.
	</li>
	<li>
		بعدها، تعمل <code>for..of</code> <em>مع ذلك الكائن المُعاد فقط لا غير</em>.
	</li>
	<li>
		حين تحتاج <code>for..of</code> القيمة التالية، تستدعي <code>next()‎</code> لذاك الكائن.
	</li>
	<li>
		يجب أن يكون ناتج <code>next()‎</code> بالشكل هذا <code>{done: Boolean, value: any}</code>، حيث لو كانت <code>done=true</code> فيعني أن التكرار اكتمل، وإلّا فقيمة <code>value</code> هي التالية.
	</li>
</ol>
<p>
	إليك النص الكامل لتنفيذ كائن <code>range</code> (مع الملاحظات):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_9" style="">
<span class="pln">let range </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  from</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  to</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// ‫‏1. حين ننادي for..of فهي تنادي هذه</span><span class="pln">
range</span><span class="pun">[</span><span class="typ">Symbol</span><span class="pun">.</span><span class="pln">iterator</span><span class="pun">]</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="com">// ‫‏...وتُعيد الكائن المُكرِّر:</span><span class="pln">
  </span><span class="com">// ‫‏2. بعد ذلك تعمل for..of مع هذا المُكرِّر، طالبةً منه القيم التالية</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    current</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">from</span><span class="pun">,</span><span class="pln">
    last</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">to</span><span class="pun">,</span><span class="pln">      

    </span><span class="com">// ‫‏3. يُستدعى next()‎ في كلّ كرّة في حلقة for..of</span><span class="pln">
    next</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

      </span><span class="com">// ‫‏4. يجب أن يُعيد القيمة كائنًا كهذا {done:.., value :...‎}</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">current </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">last</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"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">current</span><span class="pun">++</span><span class="pln"> </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">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// ‫‏والآن تعمل!</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let num of range</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">num</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫‏1، ثمّ 2 فَ‍ 3 فَ‍ 4 فَ‍ 5</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ الميزة الأساس للمُكرَّرات: فصل الاهتمامات.
</p>

<ul>
<li>
		عنصر <code>range</code> ذاته ليس له التابِع <code>next()‎</code>.
	</li>
	<li>
		بدل ذلك، يُنشأ كائن آخر (أي "المُكرَّر") عند استدعاء <code>range[Symbol.iterator]()‎</code>، وتابِعه <code>next()‎</code> يُولّد قيم التكرار.
	</li>
</ul>
<p>
	الخلاصة هي أنّ كائن المُكرَّر منفصل عن الكائن الذي يُكرِّره هذا المُكرَّر.
</p>

<p>
	نظريًا، يمكننا دمجهما معًا واستعمال كائن <code>range</code> نفسه مُتعدَّدًا لتبسيط الكود أكثر. هكذا تمامًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_11" style="">
<span class="pln">let range </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  from</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  to</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln">

  </span><span class="pun">[</span><span class="typ">Symbol</span><span class="pun">.</span><span class="pln">iterator</span><span class="pun">]()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">current </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">from</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  next</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">current </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">to</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"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">current</span><span class="pun">++</span><span class="pln"> </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">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="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="pln">let num of range</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">num</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‏1، ثمّ 2 فَ‍ 3 فَ‍ 4 فَ‍ 5</span></pre>

<p>
	الآن صار يُعيد <code>range[Symbol.iterator]()‎</code> كائن <code>range</code> نفسه: وهذا الكائن فيه تابِع <code>next()‎</code> اللازم كما ويتذكّر حالة التعداد الحالية في <code>this.current</code>. الشيفرة أبسط، أجل. وأحيانًا لا بأس به هكذا.
</p>

<p>
	المشكلة هنا هي استحالة وجود حلقتي <code>for..of</code> تعملان على الكائن في آن واحد، إذ سيتشاركان حالة التعداد؛ فليس هناك إلا مُتعدَّد واحد: الكائن نفسه. لكن أصلًا وجود حلقتي for..of نادر، حتى في العمليات غير المتزامَنة.
</p>

<p>
	<strong>مُكرَّرات لا تنتهي</strong> يمكن أيضًا ألا تنتهي المُكرَّرات أبدًا. فمثلًا لا ينتهي المدى <code>range</code> لو صار <code>range.to = Infinity</code>. يمكن أيضًا أن نصنع كائن مُتعدَّد يولّد أعدادًا شبه عشوائية (pseudorandom) لانهائية، ستفيد في حالات حرجة.
</p>

<p>
	ما من حدود مفروضة على ناتج <code>next</code>. يمكنه إعادة القيم مهما أراد وبالكم الذي أراد، لا مشكلة. طبعًا، المرور على هذا المُكرَّر بحلقة <code>for..of</code> لن ينتهي أبد الدهر، ولكن يمكننا إيقافها باستعمال <code>break</code>.
</p>

<h2>
	السلاسل النصية مُكرَّرة
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_13" style="">
<span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let </span><span class="kwd">char</span><span class="pln"> of </span><span class="str">"test"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ‫تتنفّذ أربع مرات: مرة لكلّ محرف</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">char</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫t فَ‍ e فَ‍ s فَ‍ t</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما وتعمل -كما يجب!- مع الأزواج النائبة أو البديلة (Surrogate Pairs)!
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_15" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'??'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let </span><span class="kwd">char</span><span class="pln"> of str</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">char</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>

<h2>
	نداء المُكرَّر جهارة
</h2>

<p>
	لنعرف المُكرَّرات معرفةً أعمق، لنرى كيف يمكن استعمالها جهارةً.
</p>

<p>
	سنمرّ على سلسلة نصية بنفس الطريقة التي يمرّ بها <code>for..of</code>، ولكن هذه المرة ستكون النداءات مباشرة. تُنشِئ هذه الشيفرة مُكرَّرًا لسلسلة نصية وتأخذ القيم منه "يدويًا":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_17" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// تنفّذ ما تنفّذه</span><span class="pln">
</span><span class="com">// for (let char of str) alert(char);</span><span class="pln">

</span><span class="pun">*!*</span><span class="pln">
let iterator </span><span class="pun">=</span><span class="pln"> str</span><span class="pun">[</span><span class="typ">Symbol</span><span class="pun">.</span><span class="pln">iterator</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="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let result </span><span class="pun">=</span><span class="pln"> iterator</span><span class="pun">.</span><span class="pln">next</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">result</span><span class="pun">.</span><span class="pln">done</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">result</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln"> </span><span class="com">// تطبع المحارف واحدًا تلو الآخر</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<h2>
	المُكرَّرات والشبيهات بالمصفوفات
</h2>

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

<ul>
<li>
		<em>المُكرَّرات</em> كائنات تُنفّذ التابِع <code>Symbol.iterator</code>، كما شرحنا أعلاه.
	</li>
	<li>
		<em>الشبيهات بالمصفوفات</em> كائنات لها فهارس وصفة طول <code>length</code>، وبهذا ”تشبه المصفوفات“… المصطلح يشرح نفسه.
	</li>
</ul>
<p>
	حين نستعمل جافاسكربت للمهام الحقيقية في المتصفحات وغيرها من بيئات، نقابل مختلف الكائنات أكانت مُكرَّرات أو شبيهات بالمصفوفات، أو كليهما معًا.
</p>

<p>
	السلاسل النصية مثلًا مُكرَّرة (يمكن استعمال <code>for..of</code> عليها)، وشبيهة بالمصفوفات أيضًا (لها فهارس عددية وصفة <code>length</code>). ولكن ليس من الضروري أن يكون المُكرَّر شبيه بالمصفوفة، والعكس صحيح (لا يكون الشبيه بالمصفوفة مُكرَّر). فالمدى <code>range</code> في المثال أعلاه مُكرَّر، ولكنه ليس شبيه بالمصفوفة إذ ليس فيه صفات فهارس و<code>length</code>.
</p>

<p>
	إليك كائنًا شبيهًا بالمصفوفات وليس مُكرَّرًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_19" style="">
<span class="pln">let arrayLike </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ‫فيه فهارس وطول =&gt; شبيه بالمصفوفات</span><span class="pln">
  </span><span class="lit">0</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">,</span><span class="pln">
  </span><span class="lit">1</span><span class="pun">:</span><span class="pln"> </span><span class="str">"World"</span><span class="pun">,</span><span class="pln">
  length</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="com">// ‫خطأ (ما من Symbol.iterator)</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let item of arrayLike</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{}</span></pre>

<p>
	عادةً، <em>لا تكون</em> لا المُكرَّرات ولا الشبيهات بالمصفوفات <em>مصفوفات حقًا</em>، فليس لها <code>push</code> أو <code>pop</code> وغيرها. لكن هذا غير منطقي. ماذا لو كان لدينا كائن من هذا النوع وأردنا التعامل معه بأنه مصفوفة؟ لنقل أنّا سنعمل على <code>range</code> باستعمال توابِع المصفوفات، كيف السبيل؟
</p>

<h2>
	Array.from
</h2>

<p>
	التابِع العام <a href="mdn:js/Array/from" rel="">Array.from</a> يأخذ مُكرَّرًا أو شبيهًا بالمصفوفات ويحوّله إلى مصفوفة "فعلية". بعدها ننادي توابِع المصفوفات التي نعرفها عليها.
</p>

<p>
	هكذا مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_21" style="">
<span class="pln">let arrayLike </span><span class="pun">=</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="str">"Hello"</span><span class="pun">,</span><span class="pln">
  </span><span class="lit">1</span><span class="pun">:</span><span class="pln"> </span><span class="str">"World"</span><span class="pun">,</span><span class="pln">
  length</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">

let arr </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">arrayLike</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">.</span><span class="pln">pop</span><span class="pun">());</span><span class="pln"> </span><span class="com">// ‫تكتب World (أيّ أنّ التابِع عمل)</span></pre>

<p>
	يأخذ التابِع <code>Array.from</code> في سطر <code>(*)</code> الكائن، ويفحصه أكان مُكرَّرًا أو شبيهًا بالمصفوفات، ويصنع مصفوفة جديدة ينسخ قيم ذلك الكائن فيها.
</p>

<p>
	ذات الأمر للمُكرَّرات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_23" style="">
<span class="com">// ‫نأخذ range من المثال أعلاه</span><span class="pln">
let arr </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">range</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫تكتب 1,2,3,4,5 (تحويل toString للمصفوفة يعمل)</span></pre>

<p>
	والصياغة الكاملة للتابِع <code>Array.from</code> تتيح لنا تقديم دالة ”خريطة“ اختيارية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_25" style="">
<span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">[,</span><span class="pln"> mapFn</span><span class="pun">,</span><span class="pln"> thisArg</span><span class="pun">])</span></pre>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_27" style="">
<span class="com">// ‫نأخذ range من المثال أعلاه</span><span class="pln">

</span><span class="com">// ‫نُربّع كلّ عدد</span><span class="pln">
let arr </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">range</span><span class="pun">,</span><span class="pln"> num </span><span class="pun">=&gt;</span><span class="pln"> num </span><span class="pun">*</span><span class="pln"> num</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1,4,9,16,25</span></pre>

<p>
	هنا نستعمل <code>Array.from</code> لتحويل سلسلة نصية إلى مصفوفة من المحارف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_29" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'??'</span><span class="pun">;</span><span class="pln">

</span><span class="com">// يقسم ‫str إلى مصفوفة من المحارف</span><span class="pln">
let chars </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">str</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">chars</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]);</span><span class="pln"> </span><span class="com">// ?</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">chars</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]);</span><span class="pln"> </span><span class="com">// ?</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">chars</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span></pre>

<p>
	على العكس من <code>str.split</code>، فهي هنا تعتمد على طبيعة تكراريّة السلسلة النصية، ولهذا تعمل كما ينبغي (كما تعمل <code>for..of</code>) مع الأزواج النائبة.
</p>

<p>
	هنا أيضًا تقوم بذات الفعل، نظريًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_31" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'??'</span><span class="pun">;</span><span class="pln">

let chars </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln"> </span><span class="com">// ‫داخليًا، تُنفّذ Array.from ذات الحلقة</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let </span><span class="kwd">char</span><span class="pln"> of str</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  chars</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="kwd">char</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">chars</span><span class="pun">);</span></pre>

<p>
	…ولكن تلك أقصر.
</p>

<p>
	يمكننا أيضًا صناعة تابِع <code>slice</code> مبني عليها يحترم الأزواج النائبة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9328_33" style="">
<span class="kwd">function</span><span class="pln"> slice</span><span class="pun">(</span><span class="pln">str</span><span class="pun">,</span><span class="pln"> start</span><span class="pun">,</span><span class="pln"> end</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">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">str</span><span class="pun">).</span><span class="pln">slice</span><span class="pun">(</span><span class="pln">start</span><span class="pun">,</span><span class="pln"> end</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="pun">}</span><span class="pln">

let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'???'</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> slice</span><span class="pun">(</span><span class="pln">str</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">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ??</span><span class="pln">

</span><span class="com">// ‫التابِع الأصيل/native في اللغة لا يدعم الأزواج النائبة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</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">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫يُولّد نصّ ”قمامة“ (قطعتين من أزواج نائبة مختلفة)</span></pre>

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

<p>
	تُدعى الكائنات التي يمكن استعمالها في <code>for..of</code> <em>بالمُكرَّرات (Iterables)</em>.
</p>

<ul>
<li>
		على المُكرَّرات (تقنيًا) تنفيذ التابِع بالاسم <code>Symbol.iterator</code>.

		<ul>
<li>
				يُدعى ناتج <code>obj[System.iterator]‎</code> <em>بالمُكرَّر</em>. يتعامل المُكرَّر بعملية التكرار.
			</li>
			<li>
				يجب أن يحتوي المُكرَّر التابِع بالاسم <code>next()‎</code> حيث يُعيد كائن <code>{done: Boolean, value: any}</code>… تُشير <code>done:true</code> هنا بأنّ التكرار اكتمل، وإلّا فَـ <code>value</code> هي القيمة التالية.
			</li>
		</ul>
</li>
	<li>
		تُنادي الحلقة <code>for..of</code> التابِع <code>Symbol.iterator</code> تلقائيًا عند تنفيذها، ولكن يمكننا أيضًا فعل ذلك يدويًا.
	</li>
	<li>
		تُنفّذ المُكرَّرات المضمّنة في اللغة <code>Symbol.iterator</code> (مثل السلاسل النصية والمصفوفات).
	</li>
	<li>
		مُكرَّر السلاسل النصية يفهم الأزواج البديلة.
	</li>
</ul>
<p>
	تُدعى الكائنات التي فيها صفات فهارس وصفة طول <code>length</code> <em>بالشبيهات بالمصفوفات</em>. يمكن أيضًا أن تكون لها صفات وتوابِع أخرى، إلّا أنّ ليس فيها توابِع المصفوفات المضمّنة في بنية اللغة.
</p>

<p>
	لو نظرنا ورأينا مواصفات اللغة، فسنرى بأنّ أغلب التوابِع المضمّنة فيها تتعامل مع المصفوفات على أنّها مُكرَّرات أو شبيهات بالمصفوفات بدل أن تكون مصفوفات ”حقيقية“؛ هكذا تصير أكثر تجرّديّة (abstract).
</p>

<p>
	تصنع <code>Array.from(obj[, mapFn, thisArg])‎</code> مصفوفةً <code>Array</code> حقيقية من المُكرَّر أو الشبيه بالمصفوفات <code>obj</code>، بهذا يمكن استعمال توابِع المصفوفات عليها. يتيح لنا الوسيطين <code>mapFn</code> و<code>thisArg</code> تقديم دالة لكلّ عنصر من عناصرها.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/iterable" rel="external nofollow">Iterables</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%86%D9%88%D8%B9-map-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-%D9%88%D8%A7%D9%84%D9%86%D9%88%D8%B9-set-%D8%A7%D9%84%D8%A3%D8%B7%D9%82%D9%85-r821/" rel="">النوع Map (الخرائط) والنوع Set (الأطقم)</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%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-array-methods-r819/" rel="">توابع المصفوفات (Array methods)</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">820</guid><pubDate>Thu, 12 Mar 2020 13:04:00 +0000</pubDate></item><item><title>&#x62A;&#x648;&#x627;&#x628;&#x639; &#x627;&#x644;&#x645;&#x635;&#x641;&#x648;&#x641;&#x627;&#x62A; (Array methods) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-array-methods-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r819/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/36.jpg.242f2c134ea08141f8b4aa62aa0b9aed.jpg" /></p>

<p>
	﻿تقدّم المصفوفات توابِع عديدة تُسهِّل التعامل معها. ولتبسيطها سنقسّمها إلى مجموعات بحسب الوظيفة في هذا الفصل ونشرح كل منها على حدة.
</p>

<h2>
	إضافة العناصر وإزالتها
</h2>

<p>
	عرفنا من الفصل الماضي بالتوابِع التي تُضيف العناصر وتُزيلها من بداية أو نهاية المصفوفة:
</p>

<ul>
<li>
		<code>arr.push(...items)‎</code> -- يُضيف العناصر إلى النهاية،
	</li>
	<li>
		<code>arr.pop()‎</code> -- يستخرج عنصرًا من النهاية،
	</li>
	<li>
		<code>arr.shift()‎</code> -- يستخرج عنصرًا من البداية،
	</li>
	<li>
		<code>arr.unshift(...items)‎</code> -- يُضيف العناصر إلى البداية.
	</li>
</ul>
<p>
	وهذه أخرى غيرها.
</p>

<h3>
	الوصل <code>splice</code>
</h3>

<p>
	يا ترى كيف نحذف أحد عناصر المصفوفة؟ المصفوفات كائنات، يمكننا تجربة <code>delete</code> وربما تنجح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_7" style="">
<span class="pln">let arr </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">"go"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"home"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">delete</span><span class="pln"> arr</span><span class="pun">[</span><span class="lit">1</span><span class="pun">];</span><span class="pln"> </span><span class="com">// ‫أزِل "go"</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr</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"> </span><span class="com">// undefined</span><span class="pln">

</span><span class="com">// ‫صارت المصفوفة الآن arr = ["I",  , "home"];‎</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3</span></pre>

<p>
	أُزيل العنصر صحيح، ولكنّ ما زال في المصفوفة ثلاثة عناصر، كما نرى في <code>arr.length == 3</code>.
</p>

<p>
	هذا طبيعي، إذ يُزيل <code>delete obj.key</code> القيمة بمفتاحها <code>key</code>… وهذا فقط. ينفع للكائنات ربّما، لكنّا نريدها للمصفوفات أن تنتقل كل العناصر على اليمين وتأخذ الفراغ الجديد. أي أننا نتوقع أن تصغر المصفوفة الآن.
</p>

<p>
	لهذا السبب علينا استعمال توابِع خاصّة لذلك.
</p>

<p>
	يمكننا تشبيه التابِع <a href="https://wiki.hsoub.com/JavaScript/Array/splice" rel="external">arr.splice(start)</a><code>‎</code> بالتابِع «بتاع كُلّو» للمصفوفات (كما يُقال بالعامية). يمكنه أن يُجري ما تريد للعناصر: إدراج، إزالة، استبدال.
</p>

<p>
	هذه صياغته:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_9" style="">
<span class="pln">arr</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"> deleteCount</span><span class="pun">,</span><span class="pln"> elem1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...,</span><span class="pln"> elemN</span><span class="pun">])</span></pre>

<p>
	يبدأ التابِع من عند العنصر ذي الفهرس <code>index</code>، فيُزيل <code>deleteCount</code> من العناصر ويُدرج العناصر <code>elem1, ..., elemN</code> المُمرّرة إليه مكانها. أخيرًا يُعيد المصفوفة بالعناصر المُزالة.
</p>

<p>
	فهم هذا التابِع بالأمثلة أبسط. فلنبدأ أولًا بالحذف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_25" style="">
<span class="pln">let arr </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">"study"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"JavaScript"</span><span class="pun">];</span><span class="pln">

</span><span class="com">// أزِل من العنصر ذا الفهرس 1 عنصرًا واحدًا (1)‏</span><span class="pln">
arr</span><span class="pun">.</span><span class="pln">splice</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"> 

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ["I", "JavaScript"]</span></pre>

<p>
	رأيت؟ سهلة. نبدأ من العنصر ذي الفهرس <code>1</code> ونُزيل عنصرًا واحدًا (<code>1</code>).
</p>

<p>
	الآن، نُزيل ثلاثة عناصر ونستبدلها بعنصرين آخرين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_13" style="">
<span class="pln">let arr </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">"study"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"JavaScript"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"right"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"now"</span><span class="pun">];</span><span class="pln">

</span><span class="com">// أزِل الثلاث عناصر الأولى وعوّضها بتلك الأخرى</span><span class="pln">
arr</span><span class="pun">.</span><span class="pln">splice</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Let's"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"dance"</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">)</span><span class="pln"> </span><span class="com">// ‫["Let's", "dance", "right", "now"]</span></pre>

<p>
	أمّا هنا فكيف يُعيد <code>splice</code> مصفوفةً بالعناصر المُزالة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_15" style="">
<span class="pln">let arr </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">"study"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"JavaScript"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"right"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"now"</span><span class="pun">];</span><span class="pln">

</span><span class="com">// أزِل أوّل عنصرين</span><span class="pln">
let removed </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">splice</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> removed </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "I", "study" &lt;-- قائمة بالعناصر المُزالة</span></pre>

<p>
	يمكن أن يُدرج تابِع <code>splice</code> العناصر دون إزالة أيّ شيء أيضًا. كيف؟ نضع <code>deleteCount</code> يساوي الصفر <code>0</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_23" style="">
<span class="pln">let arr </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">"study"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"JavaScript"</span><span class="pun">];</span><span class="pln">

arr</span><span class="pun">.</span><span class="pln">splice</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="str">"complex"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"language"</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "I", "study", "complex", "language", "JavaScript"</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_21" style="">
<span class="pln">let arr </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">5</span><span class="pun">];</span><span class="pln">

arr</span><span class="pun">.</span><span class="pln">splice</span><span class="pun">(-</span><span class="lit">1</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">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1,2,3,4,5</span></pre>

<h3>
	القطع <code>slice</code>
</h3>

<p>
	التابِع <a href="https://wiki.hsoub.com/JavaScript/Array/slice" rel="external">arr.slice</a> أبسط بكثير من شبيهه <code>arr.splice</code>.
</p>

<p>
	صياغته هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_27" style="">
<span class="pln">arr</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">([</span><span class="pln">start</span><span class="pun">],</span><span class="pln"> </span><span class="pun">[</span><span class="pln">end</span><span class="pun">])</span></pre>

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

<p>
	هذا التابِع يشبه تابِع السلاسل النصية <code>str.slice</code>، ولكن بدل السلاسل النصية الفرعية، يُعيد المصفوفات الفرعية. إليك المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_29" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"t"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"e"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"s"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"t"</span><span class="pun">];</span><span class="pln">

</span><span class="com">// (نسخة تبدأ من 1 وتنتهي عند 3)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</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">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// e,s </span><span class="pln">

</span><span class="com">//  ‫(نسخة تبدأ من ‎-2 وتنتهي في النهاية)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</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="pun">);</span><span class="pln"> </span><span class="com">// s,t</span></pre>

<p>
	يمكننا أيضًا استدعائها بلا وُسطاء: يُنشئ <code>arr.slice()‎</code> نسخة عن <code>arr</code>. نستعمل هذا غالبًا لأخذ نسخة وإجراء تعديلات عليها دون تعديل المصفوفة الأصلية، وتركها كما هي.
</p>

<h3>
	الربط <code>concat</code>
</h3>

<p>
	يُنشئ التابِع <a href="https://wiki.hsoub.com/JavaScript/Array/concat" rel="external">arr.concat</a> مصفوفةً جديدة فيها القيم الموجودة في المصفوفات والعناصر الأخرى.
</p>

<p>
	صياغته هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_31" style="">
<span class="pln">arr</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">arg1</span><span class="pun">,</span><span class="pln"> arg2</span><span class="pun">...)</span></pre>

<p>
	وهو يقبل أيّ عدد من الوُسطاء، أكانت مصفوفات أو قيم. أمّا ناتجه هو مصفوفة جديدة تحوي العناصر من <code>arr</code>، ثم <code>arg1</code> فَـ <code>arg2</code> وهكذا دواليك. لو كان الوسيط <code>argN</code> نفسه مصفوفة، فستُنسخ كل عناصره، وإلّا فسيُنسخ الوسيط نفسه. لاحِظ هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_33" style="">
<span class="pln">let arr </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="com">// ‫اصنع مصفوفة فيها العنصرين: arr و [3,4]</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">([</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">])</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1,2,3,4</span><span class="pln">

</span><span class="com">// ‫اصنع مصفوفة فيها العناصر: arr و[3,4] و[5,6]</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">([</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">],</span><span class="pln"> </span><span class="pun">[</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">])</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1,2,3,4,5,6</span><span class="pln">

</span><span class="com">// ‫اصنع مصفوفة فيها العنصرين: arr و[3,4]، بعدها أضِف القيمتين 5 و 6</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">([</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">],</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1,2,3,4,5,6</span></pre>

<p>
	عادةً تنسخ المصفوفة عناصر المصفوفات الأخرى. بينما الكائنات الأخرى (حتّى لو كانت مثل المصفوفات) فستُضاف كتلة كاملة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_35" style="">
<span class="pln">let arr </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">

let arrayLike </span><span class="pun">=</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="str">"something"</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="pln">
</span><span class="pun">};</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">arrayLike</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1,2,[object Object]</span></pre>

<p>
	… ولكن لو كان للكائن الشبيه بالمصفوفات خاصية <code>Symbol.isConcatSpreadable</code>، فستتعامل معه <code>concat</code> مثلما تتعامل مع المصفوفات: ستُضاف عناصره بدل كيانه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_37" style="">
<span class="pln">let arr </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">

let arrayLike </span><span class="pun">=</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="str">"something"</span><span class="pun">,</span><span class="pln">
  </span><span class="lit">1</span><span class="pun">:</span><span class="pln"> </span><span class="str">"else"</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">[</span><span class="typ">Symbol</span><span class="pun">.</span><span class="pln">isConcatSpreadable</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  length</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">

alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">arrayLike</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1,2,something,else</span></pre>

<h2>
	التكرار: لكلّ <code>forEach</code>
</h2>

<p>
	يتيح لنا التابِع <a href="https://wiki.hsoub.com/JavaScript/Array/forEach" rel="external">arr.forEach</a> تشغيل إحدى الدوال على كلّ عنصر من عناصر المصفوفة.
</p>

<p>
	الصياغة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_39" style="">
<span class="pln">arr</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">item</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ... استعملهما فيما تريد</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	مثال على عرض كلّ عنصر من عناصر المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_41" style="">
<span class="com">// ‫لكلّ عنصر، استدعِ دالة التنبيه alert</span><span class="pln">
</span><span class="pun">[</span><span class="str">"Bilbo"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Gandalf"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Nazgul"</span><span class="pun">].</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">alert</span><span class="pun">);</span></pre>

<p>
	بينما هذه الشيفرة تحبّ الكلام الزائد ومكانها في المصفوفة المحدّدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_43" style="">
<span class="pun">[</span><span class="str">"Bilbo"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Gandalf"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Nazgul"</span><span class="pun">].</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">item</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">item</span><span class="pun">}</span><span class="pln"> is at index $</span><span class="pun">{</span><span class="pln">index</span><span class="pun">}</span><span class="pln"> in $</span><span class="pun">{</span><span class="pln">array</span><span class="pun">}`);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	ناتج التابِع (لو أعادَ شيئًا أصلًا) يُهمل ويُرمى.
</p>

<h2>
	البحث في المصفوفات
</h2>

<p>
	أمّا الآن لنرى التوابع التي تبحث في المصفوفة.
</p>

<h3>
	التوابِع indexOf و lastIndexOf و includes
</h3>

<p>
	للتوابِع <a href="https://wiki.hsoub.com/JavaScript/Array/indexOf" rel="external">arr.indexOf</a> و <a href="https://wiki.hsoub.com/JavaScript/Array/lastIndexOf" rel="external">arr.lastIndexOf</a> و <a href="https://wiki.hsoub.com/JavaScript/Array/includes" rel="external">arr.includes</a> نفس الصياغة ووظيفتها هي ذات وظيفة تلك بنسخة النصوص النصية، الفرق أنها هنا تتعامل مع العناصر بدل المحارف:
</p>

<ul>
<li>
		<code>arr.indexOf(item, from)‎</code> -- يبحث عن العنصر <code>item</code> بدءًا من الفهرس <code>from</code>، ويُعيد فهرسه حيث وجده. ولو لم يجده، يُعيد <code>-1</code>.
	</li>
	<li>
		<code>arr.lastIndexOf(item, from)‎</code> -- نفسه، ولكن البحث يبدأ من اليمين وينتهي في اليسار.
	</li>
	<li>
		<code>arr.includes(item, from)‎</code> -- يبحث عن العنصر <code>item</code> بدءًا من الفهرس <code>from</code>، ويُعيد <code>true</code> إن وجدته.
	</li>
</ul>
<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_46" style="">
<span class="pln">let arr </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">0</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">indexOf</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="com">// 1</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="kwd">false</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// -1</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">includes</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"> </span><span class="com">// true</span></pre>

<p>
	لاحظ أنّ التوابِع تستعمل الموازنة بِـ <code>===</code>. لذا لو كنّا نبحث عن <code>false</code>، فستبحث هي عن <code>false</code> نفسها وليس الصفر.
</p>

<p>
	لو أردت معرفة فيما كانت تحتوي المصفوفة على عنصر معيّن، ولا تريد معرفة فهرسه، فدالة <code>arr.includes</code> مناسبة لك.
</p>

<p>
	وهناك أيضًا أمر، تختلف <code>includes</code> عن سابقاتها <code>indexOf/lastIndexOf</code> بأنّها تتعامل مع <code>NaN</code> كما ينبغي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_48" style="">
<span class="kwd">const</span><span class="pln"> arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="kwd">NaN</span><span class="pun">];</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="kwd">NaN</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫يُعيد ‎-1 (الصحيح هو 0 إلّا أنّ الموازنة === لا تعمل مع NaN)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="kwd">NaN</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="com">// true (الآن صحيح)</span></pre>

<h3>
	البحث عبر find و findIndex
</h3>

<p>
	لنقل أنّ لدينا مصفوفة من الكائنات، كيف نجد الكائن حسب شرط معيّن؟
</p>

<p>
	هنا يمكننا استغلال التابِع <a href="https://wiki.hsoub.com/JavaScript/Array/find" rel="external">arr.find(fn)</a>.
</p>

<p>
	صياغته هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_50" style="">
<span class="pln">let result </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">item</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ‫لو أُعيدت القيمة true، فيُعاد العنصر ويتوقّف التعداد</span><span class="pln">
  </span><span class="com">// ‫لو لم نجد ما نريد نُعيد undefined</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	تُستدعى الدالة على كل عنصر من عناصر المصفوفة، واحدًا بعد الآخر:
</p>

<ul>
<li>
		<code>item</code>: العنصر.
	</li>
	<li>
		<code>index</code>: الفهرس.
	</li>
	<li>
		<code>array</code>: المصفوفة نفسها.
	</li>
</ul>
<p>
	لو أعادت <code>true</code>، يتوقّف البحث ويُعاد العنصر <code>item</code>. إن لم يوجد شيء فيُعاد <code>undefined</code>.
</p>

<p>
	نرى في هذا المثال مصفوفة من المستخدمين، لكلّ مستخدم حقلان <code>id</code> و<code>name</code>. نريد الذي يتوافق مع الشرط <code>id == 1</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_52" style="">
<span class="pln">let users </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Pete"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Mary"</span><span class="pun">}</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

let user </span><span class="pun">=</span><span class="pln"> users</span><span class="pun">.</span><span class="pln">find</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">id </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// John</span></pre>

<p>
	في الحياة العملية، يكثُر استعمال الكائنات في المصفوفات، ولهذا فالتابِع <code>find</code> مفيد جدًا لنا.
</p>

<p>
	يمكنك ملاحظة بأنّا في المثال مرّرنا للتابِع <code>find</code> الدالة <code>item =&gt; item.id == 1</code> وفيها وسيط واحد. هذا طبيعي فنادرًا ما نستعمل الوُسطاء البقية في هذه الدالة.
</p>

<p>
	يتشابه التابِع <a href="https://wiki.hsoub.com/JavaScript/Array/findIndex" rel="external">arr.findIndex</a> كثيرًا مع هذا، عدا على أنّه يُعيد فهرس العنصر الذي وجده بدل العنصر نفسه، ويُعيد <code>‎-1</code> لو لم يجد شيئًا.
</p>

<h3>
	الترشيح <code>filter</code>
</h3>

<p>
	يبحث التابِع <code>find</code> عن أوّل عنصر (واحد فقط) يُحقّق للدالة شرطها فتُعيد <code>true</code>.
</p>

<p>
	لو أردت إعادة أكثر من واحد فيمكن استعمال <a href="https://wiki.hsoub.com/JavaScript/Array/filter" rel="external">arr.filter(fn)</a><a href="https://wiki.hsoub.com/JavaScript/Array/sort" rel="external">‎</a>.
</p>

<p>
	تشبه صياغة <code>filter</code> التابِع <code>find</code>، الفرق هو إعادته لمصفوفة بكلّ العناصر المتطابقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_54" style="">
<span class="pln">let results </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">item</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ‫لو كانت true فتُضاف القائمة إلى مصفوفة النتائج ويتواصل التكرار</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_1764_56" style="">
<span class="pln">let users </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Pete"</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Mary"</span><span class="pun">}</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

</span><span class="com">// يُعيد مصفوفة تحتوي على أوّل مستخدمَين اثنين</span><span class="pln">
let someUsers </span><span class="pun">=</span><span class="pln"> users</span><span class="pun">.</span><span class="pln">filter</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">id </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">3</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">someUsers</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span></pre>

<h2>
	التعديل على عناصر المصفوفات
</h2>

<p>
	لنرى الآن التوابِع التي تُعدّل المصفوفة وتُعيد ترتيبها.
</p>

<h3>
	الخارطة <code>map</code>
</h3>

<p>
	يُعدّ التابِع <a href="https://wiki.hsoub.com/JavaScript/Array/map" rel="external">arr.map</a> أكثرها استخدامًا وفائدةً أيضًا. ما يفعله هو استدعاء الدالة على كلّ عنصر من المصفوفة وإعادة مصفوفة بالنتائج.
</p>

<p>
	صياغته هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_58" style="">
<span class="pln">let result </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">item</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// يُعيد القيمة الجديدة عوض العنصر</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	مثلًا، هنا نعدّل كل عنصر فنحوّله إلى طوله:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_60" style="">
<span class="pln">let lengths </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Bilbo"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Gandalf"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Nazgul"</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">length</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">lengths</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5,7,6</span></pre>

<h3>
	sort(fn)<a href="https://wiki.hsoub.com/JavaScript/Array/sort" rel="external">‎</a>
</h3>

<p>
	نُرتّب باستدعاء <a href="https://wiki.hsoub.com/JavaScript/Array/sort" rel="external">arr.sort()‎</a> المصفوفة <em>كما هي دون نسخها</em> فنغيّر ترتيب عناصرها. هي الأخرى تُعيد المصفوفة المُرتّبة، ولكن غالبًا ما نُهمل القيمة المُعادة فالمصفوفة <code>arr</code> هي التي تتغيّر.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_62" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pln"> </span><span class="pun">];</span><span class="pln">

</span><span class="com">// يعيد التابع ترتيب محتوى المصفوفة</span><span class="pln">
arr</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln">  </span><span class="com">// 1, 15, 2</span></pre>

<p>
	هل لاحظت بأنّ الناتج غريب؟ صار <code>‎1, 15, 2</code>. ليس هذا ما نريد. ولكن، لماذا؟
</p>

<p>
	<strong>مبدئيًا، تُرتّب العناصر وكأنها سلاسل نصية.</strong>
</p>

<p>
	بالمعنى الحرفي للكلمة: تُحوّل كل العناصر إلى سلاسل نصية عند الموازنة. والترتيب المعجماتي هو المتّبع لترتيب السلاسل النصية، <code>‎"2" &gt; "15"‎</code> صحيحة حقًا.
</p>

<p>
	علينا لاستعمال الترتيب الذي نريده تمريرَ دالة تكون وسيطًا للتابِع <code>arr.sort()‎</code>.
</p>

<p>
	على الدالة موازنة قيمتين اثنتين (أيًا كانتا) وإعادة الناتج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_64" style="">
<span class="kwd">function</span><span class="pln"> compare</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</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">a </span><span class="pun">&gt;</span><span class="pln"> b</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="com">// لو تساوت القيمتين</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a </span><span class="pun">==</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</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">a </span><span class="pun">&lt;</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</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></pre>

<p>
	مثال عن الترتيب لو كانت القيم أعدادًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_66" style="">
<span class="kwd">function</span><span class="pln"> compareNumeric</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a </span><span class="pun">&gt;</span><span class="pln"> b</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">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a </span><span class="pun">==</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</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">a </span><span class="pun">&lt;</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</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">

let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pln"> </span><span class="pun">];</span><span class="pln">

arr</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">compareNumeric</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln">  </span><span class="com">// 1, 2, 15</span></pre>

<p>
	الآن صارت تعمل كما نريد.
</p>

<p>
	لنتوقف لحظة ونفكّر فيما يحدث تمامًا. أنتّفق بأنّ المصفوفة <code>arr</code> يمكن أن تحتوي أيّ شيء؟ أيّ شيء من الأعداد أو السلاسل النصية أو الكائنات أو غيرها. كلّ ما لدينا هو <em>مجموعة من العناصر</em>. لترتيبها نحتاج <em>دالة ترتيب</em> تعرف طرقة مقارنة عناصر المصفوفة. مبدئيًا، الترتيب يكون بالسلاسل النصية.
</p>

<p>
	يُنفِّذ التابع <code>arr.sort(fn)‎</code>في طيّاته خوارزمية فرز عامّة. لسنا نكترث كيف تعمل هذه الخوارزمية خلف الكواليس (وهي غالبًا <a href="https://en.wikipedia.org/wiki/Quicksort" rel="external nofollow">quicksort</a> محسّنة)، بل نكترث بأنّها ستمرّ على المصفوفة، تُوازن عناصرها باستعمال الدالة المقدّمة أعلاه وتُعيد ترتيبها. نكترث بأن نقدّم دالة <code>fn</code> التي ستؤدّي الموازنة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_68" style="">
<span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2</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">2</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">8</span><span class="pun">].</span><span class="pln">sort</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> </span><span class="str">" &lt;&gt; "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> b </span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	يمكن أن تقارن الخوارزمية العنصر مع غيره من العناصر، ولكنّها تحاول قدر الإمكان تقليص عدد الموازنات.
</p>

<p>
	<strong>يمكن أن تُعيد دالة الموازنة أيّ عدد</strong> في الواقع، ليس على دالة الموازنة إلّا إعادة عدد موجب بدلالة «هذا أكبر من ذاك» وسالب بدلالة «هذا أصغر من ذاك».
</p>

<p>
	يمكننا هكذا كتابة الدوال بأسطر أقل: That allows to write shorter functions:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_70" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pln"> </span><span class="pun">];</span><span class="pln">

arr</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">-</span><span class="pln"> b</span><span class="pun">;</span><span class="pln"> </span><span class="pun">});</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln">  </span><span class="com">// 1, 2, 15</span></pre>

<p>
	<strong>تحيا الدوال السهمية</strong> أتذكر <a href="https://wiki.hsoub.com/JavaScript/Arrow_Functions" rel="external">الدوال السهمية</a> من فصل <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%88%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B3%D9%87%D9%85%D9%8A%D8%A9-r782/" rel="">تعابير الدوال والدوال السهمية</a>؟ يمكننا استعمالها أيضًا لتبسيط كود الفرز:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_72" style="">
<span class="pln">arr</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> a </span><span class="pun">-</span><span class="pln"> b </span><span class="pun">);</span></pre>

<p>
	لا تفرق هذه عن تلك الطويلة بشيء، البتة.
</p>

<h3>
	العكس <code>reverse</code>
</h3>

<p>
	يعكس التابِع <a href="https://wiki.hsoub.com/JavaScript/Array/reverse" rel="external">arr.reverse</a> ترتيب العناصر في المصفوفة <code>arr</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_74" style="">
<span class="pln">let arr </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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span><span class="pln">
arr</span><span class="pun">.</span><span class="pln">reverse</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5,4,3,2,1</span></pre>

<p>
	كما ويُعيد المصفوفة <code>arr</code> بعد عكسها.
</p>

<h3>
	التقسيم <code>split</code> والدمج <code>join</code>
</h3>

<p>
	إليك موقفًا من الحياة العملية. تحاول الآن برمجة تطبيق مراسلة، ويُدخل المستخدم قائمة المستلمين بفاصلة بين كلّ واحد: <code>John, Pete, Mary</code>. ولكن لنا نحن المبرمجين، فالمصفوفة التي تحتوي الأسماء أسهل بكثير من السلسلة النصية. كيف السبيل إذًا؟
</p>

<p>
	هذا ما يفعله التابِع <a href="https://wiki.hsoub.com/JavaScript/String/split" rel="external">str.split(delim)</a><code>‎</code>. يأخذ السلسلة النصية ويقسمها إلى مصفوفة حسب محرف القاسِم <code>delim</code> المقدّم.
</p>

<p>
	في المثال أعلاه نقسم حسب «فاصلة بعدها مسافة»:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_76" style="">
<span class="pln">let names </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Bilbo, Gandalf, Nazgul'</span><span class="pun">;</span><span class="pln">

let arr </span><span class="pun">=</span><span class="pln"> names</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">', '</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let name of arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`</span><span class="pln">A message to $</span><span class="pun">{</span><span class="pln">name</span><span class="pun">}.`</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// A message to Bilbo  (والبقية)</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_78" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Bilbo, Gandalf, Nazgul, Saruman'</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">', '</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Bilbo, Gandalf</span></pre>

<p>
	<strong>التقسيم إلى أحرف</strong> لو ناديت <code>split(s)‎</code> وتركت <code>s</code> فارغًا فستُسقم السلسلة النصية إلى مصفوفة من الأحرف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_80" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"test"</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// t,e,s,t</span></pre>

<p>
	على العكس من <code>split</code> فنداء <a href="https://wiki.hsoub.com/JavaScript/Array/join" rel="external">arr.join(glue)</a><code>‎</code> يُنشئ سلسلة نصية من عناصر <code>arr</code> مجموعةً معًا «باللاصق».
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_82" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Bilbo'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Gandalf'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Nazgul'</span><span class="pun">];</span><span class="pln">

let str </span><span class="pun">=</span><span class="pln"> arr</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">

alert</span><span class="pun">(</span><span class="pln"> str </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Bilbo;Gandalf;Nazgul</span></pre>

<h3>
	التابِعان reduce و reduceRight
</h3>

<p>
	متى ما أردنا أن نمرّ على عناصر المصفوفة، استعملنا <code>forEach</code> أو <code>for</code> أو <code>for..of</code>. ومتى ما أردنا أن نمرّ ونُعيد بيانات كلّ عنصر، استعملنا <code>map</code>.
</p>

<p>
	نفس الحال مع التابعين <a href="https://wiki.hsoub.com/JavaScript/Array/reduce" rel="external">arr.reduce</a> و<a href="https://wiki.hsoub.com/JavaScript/Array/reduceRight" rel="external">arr.reduceRight</a>، إلّا أنهما ليسا بالسهولة نفسها. يُستعمل هذان التابعان لحساب قيمة واحدة حسب عناصر المصفوفة.
</p>

<p>
	هذه الصياغة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_84" style="">
<span class="pln">let value </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">reduce</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">previousValue</span><span class="pun">,</span><span class="pln"> item</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">[</span><span class="pln">initial</span><span class="pun">]);</span></pre>

<p>
	تُطبّق الدالة على كل عناصر المصفوفة واحدًا بعد الآخر، و«تنقل» النتيجة إلى النداء التالي لها:
</p>

<p>
	وُسطاء الدالة:
</p>

<ul>
<li>
		<code>previousValue</code> - نتيجة النداء السابق للدالة. يُساوي قيمة <code>initial</code> في أوّل نداء (لو قُدّمت أصلًا).
	</li>
	<li>
		<code>item</code> -- العنصر الحالي في المصفوفة.
	</li>
	<li>
		<code>index</code> -- مكان العنصر.
	</li>
	<li>
		<code>array</code> -- المصفوفة نفسها.
	</li>
</ul>
<p>
	حين تُطبّق الدالة، تُمرّر إليها نتيجة النداء السابق في أوّل وسيط. أجل، معقّد قليلًا، لكن ليس كما تتخيّل لو قلنا أنّ الوسيط الأول بمثابة «ذاكرة» تخزّن النتيجة النهائية من إجراءات التنفيذ التي سبقتها. وفي آخر نداء تصير نتيجة التابِع <code>reduce</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_86" style="">
<span class="pln">let arr </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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span><span class="pln">

let result </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">reduce</span><span class="pun">((</span><span class="pln">sum</span><span class="pun">,</span><span class="pln"> current</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> sum </span><span class="pun">+</span><span class="pln"> current</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">result</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 15</span></pre>

<p>
	الدالة المُمرّرة إلى <code>reduce</code> تستعمل وسيطين اثنين فقط، وهذا كافٍ عادةً.
</p>

<p>
	لنرى تفاصيل النداءات.
</p>

<ol>
<li>
		في أوّل مرّة، قيمة <code>sum</code> هي قيمة <code>initial</code> (آخر وسيط في <code>reduce</code>) وتساوي <code>0</code>، و<code>current</code> هي أوّل عنصر في المصفوفة وتساوي <code>1</code>. إذًا فناتج الدالة هو <code>1</code>.
	</li>
	<li>
		في النداء التالي، <code>sum = 1</code> ونُضيف العنصر الثاني في المصفوفة (<code>2</code>) ونُعيد القيمة.
	</li>
	<li>
		في النداء الثالث، <code>sum = 3</code>، ونُضيف العنصر التالي في المصفوفة، وهكذا دواليك إلى آخر نداء…
	</li>
</ol>
<p>
	هذا سير العملية الحسابية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="33718" href="https://academy.hsoub.com/uploads/monthly_2020_02/reduce.png.a7c65e6c047878c9de6da51c37e03b3f.png" rel=""><img alt="reduce.png" class="ipsImage ipsImage_thumbnailed" data-fileid="33718" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/reduce.png.a7c65e6c047878c9de6da51c37e03b3f.png"></a>
</p>

<p>
	وهكذا نمثّلها في جدول (كلّ صف يساوي نداء واحد للدالة على العنصر التالي في المصفوفة):
</p>

<table>
<thead><tr>
<th>
				 
			</th>
			<th>
				<code>sum</code>
			</th>
			<th>
				<code>current</code>
			</th>
			<th>
				الناتج
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				أوّل نداء
			</td>
			<td>
				<code>0</code>
			</td>
			<td>
				<code>1</code>
			</td>
			<td>
				<code>1</code>
			</td>
		</tr>
<tr>
<td>
				ثاني نداء
			</td>
			<td>
				<code>1</code>
			</td>
			<td>
				<code>2</code>
			</td>
			<td>
				<code>3</code>
			</td>
		</tr>
<tr>
<td>
				ثالث نداء
			</td>
			<td>
				<code>3</code>
			</td>
			<td>
				<code>3</code>
			</td>
			<td>
				<code>6</code>
			</td>
		</tr>
<tr>
<td>
				رابع نداء
			</td>
			<td>
				<code>6</code>
			</td>
			<td>
				<code>4</code>
			</td>
			<td>
				<code>10</code>
			</td>
		</tr>
<tr>
<td>
				خامس نداء
			</td>
			<td>
				<code>10</code>
			</td>
			<td>
				<code>5</code>
			</td>
			<td>
				<code>15</code>
			</td>
		</tr>
</tbody>
</table>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
}

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<p>
	هكذا نرى بوضوح شديد كيف يصير ناتج النداء السابق أوّل وسيط في النداء الذي يلحقه.
</p>

<p>
	يمكننا أيضًا حذف القيمة الأولية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_88" style="">
<span class="pln">let arr </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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span><span class="pln">

</span><span class="com">// ‫أزلنا القيمة الأولية من التابِع reduce (اختفت القيمة 0)</span><span class="pln">
let result </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">reduce</span><span class="pun">((</span><span class="pln">sum</span><span class="pun">,</span><span class="pln"> current</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> sum </span><span class="pun">+</span><span class="pln"> current</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> result </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 15</span></pre>

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

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

<p>
	مثال على ذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_90" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">

arr</span><span class="pun">.</span><span class="pln">reduce</span><span class="pun">((</span><span class="pln">sum</span><span class="pun">,</span><span class="pln"> current</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> sum </span><span class="pun">+</span><span class="pln"> current</span><span class="pun">);</span></pre>

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

<p>
	لا يختلف التابِع <a href="https://wiki.hsoub.com/JavaScript/Array/reduceRight" rel="external">arr.reduceRight</a> عن هذا أعلاه إلا بأنّه يبدأ من اليمين وينتهي على اليسار.
</p>

<h2>
	Array.isArray
</h2>

<p>
	المصفوفات ليست نوعًا منفصلًا في اللغة، بل هي مبنيّة على الكائنات. لذا <code>typeof</code> لن تفيدك في التفريق بين الكائن العادي والمصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_92" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="kwd">typeof</span><span class="pln"> </span><span class="pun">{});</span><span class="pln"> </span><span class="com">// ‫كائن object</span><span class="pln">
alert</span><span class="pun">(</span><span class="kwd">typeof</span><span class="pln"> </span><span class="pun">[]);</span><span class="pln"> </span><span class="com">// كائن أيضًا</span></pre>

<p>
	…ولكن، المصفوفات تستعمل كثيرًا جدًا لدرجة تقديم تابِع خاص لهذا الغرض: <a href="https://wiki.hsoub.com/JavaScript/Array/isArray" rel="external">Array.isArray(value)</a><code>‎</code>. يُعيد هذا التابِع <code>true</code> لو كانت <code>value</code> مصفوفة حقًا، و<code>false</code> لو لم تكن.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_94" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="typ">Array</span><span class="pun">.</span><span class="pln">isArray</span><span class="pun">({}));</span><span class="pln"> </span><span class="com">// false</span><span class="pln">

alert</span><span class="pun">(</span><span class="typ">Array</span><span class="pun">.</span><span class="pln">isArray</span><span class="pun">([]));</span><span class="pln"> </span><span class="com">// true</span></pre>

<h2>
	تدعم أغلب التوابِع <code>thisArg</code>
</h2>

<p>
	تقبل أغلب توابِع المصفوفات تقريبًا، التوابع التي تستدعي دوالًا (مثل <code>find</code> و<code>filter</code> و<code>map</code>، عدا <code>sort</code>) - تقبل المُعامل الاختياري <code>thisArg</code>.
</p>

<p>
	لم نشرح هذا المُعامل في الأقسام أعلاه إذ أنّه نادرًا ما يُستعمل. ولكن علينا الحديث عنه لألا يكون الشرح ناقصًا.
</p>

<p>
	هذه الصياغة الكاملة لهذه التوابِع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_96" style="">
<span class="pln">arr</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">func</span><span class="pun">,</span><span class="pln"> thisArg</span><span class="pun">);</span><span class="pln">
arr</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">func</span><span class="pun">,</span><span class="pln"> thisArg</span><span class="pun">);</span><span class="pln">
arr</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">func</span><span class="pun">,</span><span class="pln"> thisArg</span><span class="pun">);</span><span class="pln">
</span><span class="com">// ...</span><span class="pln">
</span><span class="com">// ‫الوسيط thisArg هو آخر وسيط اختياري</span></pre>

<p>
	تكون قيمة المُعامل <code>thisArg</code> للدالة <code>func</code> تساوي <code>this</code>. هنا مثلًا نستعمل تابِع كائن <code>army</code> على أنّه مرشّح، والوسيط <code>thisArg</code> يمرّر سياق التنفيذ وذلك لإيجاد المستخدمين الذين يعيد التابع <code>army.canJoin</code> القيمة <code>true</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_98" style="">
<span class="pln">let army </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  minAge</span><span class="pun">:</span><span class="pln"> </span><span class="lit">18</span><span class="pun">,</span><span class="pln">
  maxAge</span><span class="pun">:</span><span class="pln"> </span><span class="lit">27</span><span class="pun">,</span><span class="pln">
  canJoin</span><span class="pun">(</span><span class="pln">user</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"> user</span><span class="pun">.</span><span class="pln">age </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">minAge </span><span class="pun">&amp;&amp;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">age </span><span class="pun">&lt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maxAge</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let users </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">16</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">23</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">}</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

</span><span class="pun">*!*</span><span class="pln">

let soldiers </span><span class="pun">=</span><span class="pln"> users</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">army</span><span class="pun">.</span><span class="pln">canJoin</span><span class="pun">,</span><span class="pln"> army</span><span class="pun">);</span><span class="pln">
</span><span class="pun">*/!*</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">soldiers</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">soldiers</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">age</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 20</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">soldiers</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">age</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 23</span></pre>

<p>
	لو استعملنا في المثال أعلاه <code>users.filter(army.canJoin)‎</code> فسيُستدعى التابِع <code>army.canJoin</code> كدالة مستقلة بذاتها حيث <code>this=undefined</code>، ما سيؤدي إلى خطأ.
</p>

<p>
	يمكن استبدال استدعاء <code>users.filter(army.canJoin, army)‎</code> بالتعليمة التي تُؤدّي ذات الغرض <code>users.filter(user =&gt; army.canJoin(user))‎</code>. نستعمل الأولى أكثر من الثانية إذ أنّ الناس تفهمها أكثر من تلك.
</p>

<h2>
	ملخص
</h2>

<p>
	ورقة فيها كل توابِع الدوال (غُشّ منها):
</p>

<ul>
<li>
		<p>
			لإضافة العناصر وإزالتها:
		</p>

		<ul>
<li>
				<p>
					<code>push(...items)‎</code> -- تُضيف العناصر <code>items</code> إلى النهاية،
				</p>
			</li>
			<li>
				<p>
					<code>pop()‎</code> -- تستخرج عنصرًا من النهاية،
				</p>
			</li>
			<li>
				<p>
					<code>shift()‎</code> -- تستخرج عنصرًا من البداية،
				</p>
			</li>
			<li>
				<p>
					<code>unshift(...items)‎</code> -- تُضيف العناصر <code>items</code> إلى البداية.
				</p>
			</li>
			<li>
				<p>
					<code>splice(pos, deleteCount, ...items)‎</code> -- بدءًا من العنصر ذي الفهرس <code>pos</code>، احذف <code>deleteCount</code> من العناصر وأدرِج مكانه العناصر <code>items</code>.
				</p>
			</li>
			<li>
				<p>
					<code>slice(start, end)‎</code> -- أنشِئ مصفوفة جديدة وانسخ عناصرها بدءًا من start <code>وحتّى</code>end<code>(ولكن دون</code>end).
				</p>
			</li>
			<li>
				<p>
					<code>concat(...items)‎</code> -- أعِد مصفوفة جديدة: انسخ كل عناصر المصفوفة الحالية وأضَِف إليها العناصر <code>items</code>. لو كانت واحدة من عناصر <code>items</code> مصفوفة أيضًا، فستُنسخ عناصرها بدل.
				</p>
			</li>
		</ul>
</li>
	<li>
		<p>
			لتبحث عن العناصر:
		</p>

		<ul>
<li>
				<p>
					<code>indexOf/lastIndexOf(item, pos)‎</code> -- ابحث عن العنصر <code>item</code> بدءًا من العنصر ذي الفهرس <code>pos</code> وأعِد فهرسه أو أعِد <code>‎-1</code> لو لم تجده.
				</p>
			</li>
			<li>
				<p>
					<code>includes(value)‎</code> -- أعِد القيمة <code>true</code> لو كان العنصر <code>value</code> في المصفوفة، وإلا أعِد <code>false</code>.
				</p>
			</li>
			<li>
				<p>
					<code>find/filter(func)‎</code> -- رشّح العناصر عبر دالة وأعِد أوّل قيمة (أو كل القيم) التي تُعيد الدالة قيمة <code>true</code> لو مُرّر ذلك العنصر لها.
				</p>
			</li>
			<li>
				<p>
					<code>findIndex</code> يشبه <code>find</code>، ولكن يُعيد الفهرس بدل القيمة.
				</p>
			</li>
		</ul>
</li>
	<li>
		<p>
			للمرور على عناصر المصفوفة:
		</p>

		<ul>
<li>
				<p>
					<code>forEach(func)‎</code> -- يستدعي <code>func</code> لكلّ عنصر ولا يُعيد أيّ شيء.
				</p>
			</li>
		</ul>
</li>
	<li>
		<p>
			لتعديل عناصر المصفوفة:
		</p>

		<ul>
<li>
				<p>
					<code>map(func)‎</code> -- أنشِئ مصفوفة جديدة من نتائج استدعاء <code>func</code> لكلّ من عناصر المصفوفة.
				</p>
			</li>
			<li>
				<p>
					<code>sort(func)‎</code> -- افرز المصفوفة كما هي وأعِد ناتج الفرز.
				</p>
			</li>
			<li>
				<p>
					<code>reverse()‎</code> -- اعكس عناصر المصفوفة كما هي وأعِد ناتج العكس.
				</p>
			</li>
			<li>
				<p>
					<code>split/join</code> -- حوّل المصفوفة إلى سلسلة نصية، والعكس أيضًا.
				</p>
			</li>
			<li>
				<p>
					<code>reduce(func, initial)‎</code> -- احسب قيمة من المصفوفة باستدعاء <code>func</code> على كلّ عنصر فيها وتمرير الناتج بين كلّ استدعاء وآخر.
				</p>
			</li>
		</ul>
</li>
	<li>
		<p>
			وأيضًا:
		</p>

		<ul>
<li>
				<p>
					<code>Array.isArray(arr)‎</code> يفحص لو كانت <code>arr</code> مصفوفة أم لا.
				</p>
			</li>
		</ul>
</li>
</ul>
<p>
	لاحظ أنّ التوابِع <code>sort</code> و<code>reverse</code> و<code>splice</code> تُعدّل المصفوفة نفسها.
</p>

<p>
	هذه التوابِع أعلاه هي أغلب ما تحتاج وما تريد أغلب الوقت (99.99%). ولكن هناك طبعًا غيرها:
</p>

<ul>
<li>
		<p>
			<a href="https://wiki.hsoub.com/JavaScript/Array/some" rel="external"><code>arr.some(fn)‎</code></a>/<a href="https://wiki.hsoub.com/JavaScript/Array/every" rel="external">arr.every(fn)</a><code>‎</code> تفحص المصفوفة.
		</p>

		<p>
			تُنادى الدالة <code>fn</code> على كلّ عنصر من المصفوفة (مثل <code>map</code>). لو كانت أيًا من (أو كل) النتائج <code>true</code>، فيُعيد <code>true</code>، وإلًا يُعيد <code>false</code>.
		</p>
	</li>
	<li>
		<p>
			<a href="https://wiki.hsoub.com/JavaScript/Array/fill" rel="external"><code>arr.fill(value, start, end)‎</code>‎</a> -- يملأ المصفوفة بالقيمة المتكرّرة <code>value</code> من الفهرس <code>start</code> إلى الفهرس <code>end</code>.
		</p>
	</li>
	<li>
		<p>
			<a href="https://wiki.hsoub.com/JavaScript/Array/copyWithin" rel="external"><code>arr.copyWithin(target, start, end)‎</code>‎</a> -- ينسخ العناصر من العنصر ذا الفهرس <code>start</code> إلى ذا الفهرس <code>end</code> ويلصقها <em>داخلها</em> عند الفهرس <code>target</code> (تعوّض ما هو موجود مكانها في المصفوفة).
		</p>
	</li>
</ul>
<p>
	طالِع <a href="https://wiki.hsoub.com/JavaScript/Array" rel="external">الكتيّب</a> لقائمة فيها كل شيء. من أول وهلة سترى بأنّ عدد التوابِع لا ينتهي ومهمة حفظها مستحيلة، ولكن الواقع هي أنّها بسيطة جدًا.
</p>

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

<h2>
	تمارين
</h2>

<h3>
	حوّل «border-left-width» إلى «borderLeftWidth»
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	اكتب دالة <code>camelize(str)‎</code> تغيّر الكلمات المقسومة بِشَرطات مثل «my-short-string» إلى عبارات بتنسيق «سنام الجمل»: «myShortString».
</p>

<p>
	بعبارة أخرى: أزِل كلّ الشرطات وحوّل أوّل حرف من كلّ كلمة بعدها إلى الحالة الكبيرة.
</p>

<p>
	أمثلة:
</p>

<pre class="ipsCode">
camelize("background-color") == 'backgroundColor';
camelize("list-style-image") == 'listStyleImage';
camelize("-webkit-transition") == 'WebkitTransition';
</pre>

<p>
	تلميح: استعمل <code>split</code> لتقسيم السلسلة النصية إلى مصفوفة، ثمّ عدّل عناصرها وأعِد ربطها بتابِع <code>join</code>.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_101" style="">
<span class="kwd">function</span><span class="pln"> camelize</span><span class="pun">(</span><span class="pln">str</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"> str
    </span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">'-'</span><span class="pun">)</span><span class="pln"> </span><span class="com">// splits 'my-long-word' into array ['my', 'long', 'word']</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">
      </span><span class="com">// كبر الحروف الأولى لجميع عناصر المصفوفة باستثناء أول عنصر</span><span class="pln">
      </span><span class="com">// ['my', 'long', 'word'] --&gt; ['my', 'Long', 'Word']</span><span class="pln">
      </span><span class="pun">(</span><span class="pln">word</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> index </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> word </span><span class="pun">:</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">toUpperCase</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> word</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="pun">)</span><span class="pln">
    </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">// joins ['my', 'Long', 'Word'] into 'myLongWord'</span><span class="pln">
</span><span class="pun">}</span></pre>
</div>

<h3>
	نطاق ترشيح
</h3>

<p class="task__importance">
	<em>الأهمية: 4</em>
</p>

<p>
	اكتب دالة <code>filterRange(arr, a, b)‎</code> تأخذ المصفوفة <code>arr</code>، وتبحث في عناصرها بين <code>a</code> و<code>b</code> وتُعيد مصفوفة بها. يجب ألّا تُعدّل الدالة المصفوفة، بل إعادة مصفوفة جديدة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_103" style="">
<span class="pln">let arr </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">3</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">1</span><span class="pun">];</span><span class="pln">

let filtered </span><span class="pun">=</span><span class="pln"> filterRange</span><span class="pun">(</span><span class="pln">arr</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">4</span><span class="pun">);</span><span class="pln"> 

alert</span><span class="pun">(</span><span class="pln"> filtered </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3,1</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5,3,8,1</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_105" style="">
<span class="kwd">function</span><span class="pln"> filterRange</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">,</span><span class="pln"> a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// أضفنا الأقواس حول التعبير لتسهيل القراءة</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">item </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a </span><span class="pun">&lt;=</span><span class="pln"> item </span><span class="pun">&amp;&amp;</span><span class="pln"> item </span><span class="pun">&lt;=</span><span class="pln"> b</span><span class="pun">));</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let arr </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">3</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">1</span><span class="pun">];</span><span class="pln">

let filtered </span><span class="pun">=</span><span class="pln"> filterRange</span><span class="pun">(</span><span class="pln">arr</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">4</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> filtered </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3,1</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5,3,8,1</span></pre>
</div>

<h3>
	نطاق ترشيح «كما هو»
</h3>

<p class="task__importance">
	<em>الأهمية: 4</em>
</p>

<p>
	اكتب دالة <code>filterRangeInPlace(arr, a, b)‎</code> تأخذ المصفوفة <code>arr</code> وتُزيل منها كل القيم عدا تلك بين <code>a</code> و<code>b</code>. الشرط هو: <code>‎a ≤ arr<em> ≤ b</em></code><em>. </em>
</p>

<p>
	يجب أن تُعدّل الدالة المصفوفة، ولا تُعيد شيئًا.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_107" style="">
<span class="pln">let arr </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">3</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">1</span><span class="pun">];</span><span class="pln">

</span><span class="com">// حذف جميع الأعداد باستثناء الواقعة بين 1 و 4</span><span class="pln">
filterRangeInPlace</span><span class="pun">(</span><span class="pln">arr</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">4</span><span class="pun">);</span><span class="pln"> 

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// [3, 1]</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_109" style="">
<span class="kwd">function</span><span class="pln"> filterRangeInPlace</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">,</span><span class="pln"> a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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"> arr</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let val </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">[</span><span class="pln">i</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">val </span><span class="pun">&lt;</span><span class="pln"> a </span><span class="pun">||</span><span class="pln"> val </span><span class="pun">&gt;</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      arr</span><span class="pun">.</span><span class="pln">splice</span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
      i</span><span class="pun">--;</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">

let arr </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">3</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">1</span><span class="pun">];</span><span class="pln">

filterRangeInPlace</span><span class="pun">(</span><span class="pln">arr</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">4</span><span class="pun">);</span><span class="pln"> </span><span class="com">// removed the numbers except from 1 to 4</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// [3, 1]</span></pre>
</div>

<h3>
	الفرز بالترتيب التنازلي
</h3>

<p class="task__importance">
	الأهمية: 4
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_111" style="">
<span class="pln">let arr </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">1</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">8</span><span class="pun">];</span><span class="pln">

</span><span class="com">// ... شيفرة ترتيب العناصر تنازليًا</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 8, 5, 2, 1, -10</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_113" style="">
<span class="pln">let arr </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">1</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">8</span><span class="pun">];</span><span class="pln">

arr</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">((</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> b </span><span class="pun">-</span><span class="pln"> a</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span></pre>
</div>

<h3>
	نسخ المصفوفة وفرزها
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	في يدنا مصفوفة من السلاسل النصية <code>arr</code>. نريد نسخة مرتّبة عنها وترك <code>arr</code> بلا تعديل.
</p>

<p>
	أنشِئ دالة <code>copySorted(arr)‎</code> تُعيد هذه النسخة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_115" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"HTML"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"JavaScript"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"CSS"</span><span class="pun">];</span><span class="pln">

let sorted </span><span class="pun">=</span><span class="pln"> copySorted</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> sorted </span><span class="pun">);</span><span class="pln"> </span><span class="com">// CSS, HTML, JavaScript</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// HTML, JavaScript, CSS</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		يمكن أن نستعمل <code>slice()‎</code> لأخذ نسخة ونفرز المصفوفة:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_117" style="">
<span class="kwd">function</span><span class="pln"> copySorted</span><span class="pun">(</span><span class="pln">arr</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"> arr</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">().</span><span class="pln">sort</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"HTML"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"JavaScript"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"CSS"</span><span class="pun">];</span><span class="pln">

</span><span class="pun">*!*</span><span class="pln">
let sorted </span><span class="pun">=</span><span class="pln"> copySorted</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln">
</span><span class="pun">*/!*</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> sorted </span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span></pre>
</div>

<h3>
	خارطة بالأسماء
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	لدينا مصفوفة من كائنات <code>user</code>، لكلّ منها صفة <code>user.name</code>. اكتب كودًا يحوّلها إلى مصفوفة من الأسماء.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_119" style="">
<span class="pln">let john </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">"John"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let pete </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">"Pete"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let mary </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">"Mary"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">28</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

let users </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> john</span><span class="pun">,</span><span class="pln"> pete</span><span class="pun">,</span><span class="pln"> mary </span><span class="pun">];</span><span class="pln">

let names </span><span class="pun">=</span><span class="pln"> </span><span class="com">/* شيفرتك هنا */</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> names </span><span class="pun">);</span><span class="pln"> </span><span class="com">// John, Pete, Mary</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_121" style="">
<span class="pln">let john </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">"John"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let pete </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">"Pete"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let mary </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">"Mary"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">28</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

let users </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> john</span><span class="pun">,</span><span class="pln"> pete</span><span class="pun">,</span><span class="pln"> mary </span><span class="pun">];</span><span class="pln">

let names </span><span class="pun">=</span><span class="pln"> users</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">name</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> names </span><span class="pun">);</span><span class="pln"> </span><span class="com">// John, Pete, Mary</span></pre>
</div>

<h3>
	أنشِئ آلة حاسبة يمكن توسعتها لاحقًا
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	أنشِئ دالة إنشاء باني «constructor»‏ <code>Calculator</code> تُنشئ كائنات من نوع «آلة حاسبة» يمكن لنا «توسعتها».
</p>

<p>
	تنقسم هذه المهمة إلى جزئين اثنين:
</p>

<ol>
<li>
		<p>
			أولًا، نفّذ تابِع <code>calculate(str)‎</code> يأخذ سلسلة نصية (مثل <code>"1 + 2"</code>) بالتنسيق «عدد مُعامل عدد» (أي مقسومة بمسافات) ويُعيد الناتج. يجب أن يفهم التابِع الجمع <code>+</code> والطرح <code>-</code>.
		</p>

		<p>
			مثال عن الاستعمال:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_123" style="">
<span class="pln">let calc </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Calculator</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> calc</span><span class="pun">.</span><span class="pln">calculate</span><span class="pun">(</span><span class="str">"3 + 7"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 10</span></pre>

		<p>
			 
		</p>
	</li>
	<li>
		<p>
			بعدها أضِف تابِع <code>addMethod(name, func)‎</code> يُعلّم الآلة الحاسبة عمليّة جديدة. يأخذ التابِع المُعامل <code>name</code> ودالة <code>func(a,b)‎</code> بوسيطين تُنفّذ هذه العملية.
		</p>

		<p>
			كمثال على ذلك سنُضيف عمليات الضرب <code>*</code> والقسمة <code>/</code> والأُسّ <code>**</code>:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_125" style="">
<span class="pln">let powerCalc </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Calculator</span><span class="pun">;</span><span class="pln">
powerCalc</span><span class="pun">.</span><span class="pln">addMethod</span><span class="pun">(</span><span class="str">"*"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> a </span><span class="pun">*</span><span class="pln"> b</span><span class="pun">);</span><span class="pln">
powerCalc</span><span class="pun">.</span><span class="pln">addMethod</span><span class="pun">(</span><span class="str">"/"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> a </span><span class="pun">/</span><span class="pln"> b</span><span class="pun">);</span><span class="pln">
powerCalc</span><span class="pun">.</span><span class="pln">addMethod</span><span class="pun">(</span><span class="str">"**"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> a </span><span class="pun">**</span><span class="pln"> b</span><span class="pun">);</span><span class="pln">

let result </span><span class="pun">=</span><span class="pln"> powerCalc</span><span class="pun">.</span><span class="pln">calculate</span><span class="pun">(</span><span class="str">"2 ** 3"</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> result </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 8</span></pre>

		<p>
			 
		</p>
	</li>
</ol>
<ul>
<li>
		في هذه المهمة ليس هناك أقواس رياضية أو تعابير معقّدة.
	</li>
	<li>
		تفصل الأعداد والمُعامل مسافة واحدة فقط.
	</li>
	<li>
		يمكنك التعامل مع الأخطاء لو أردت.
	</li>
</ul>
<h4>
	الحل
</h4>

<div class="task__answer">
	<ul>
<li>
			لاحظ طريقة تخزين التوابِع، حيث تُضاف إلى صفة <code>this.methods</code> فقط.
		</li>
		<li>
			كلّ الشروط والتحويلات العددية موجودة في التابِع <code>calculate</code>. يمكننا في المستقبل توسيعه ليدعم تعابير أكثر تعقيدًا.
		</li>
	</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_127" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Calculator</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">methods </span><span class="pun">=</span><span class="pln"> </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">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> a </span><span class="pun">-</span><span class="pln"> b</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">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b
  </span><span class="pun">};</span><span class="pln">

  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">calculate </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">str</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    let split </span><span class="pun">=</span><span class="pln"> str</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">
      a </span><span class="pun">=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">split</span><span class="pun">[</span><span class="lit">0</span><span class="pun">],</span><span class="pln">
      op </span><span class="pun">=</span><span class="pln"> split</span><span class="pun">[</span><span class="lit">1</span><span class="pun">],</span><span class="pln">
      b </span><span class="pun">=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">split</span><span class="pun">[</span><span class="lit">2</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">methods</span><span class="pun">[</span><span class="pln">op</span><span class="pun">]</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> isNaN</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> isNaN</span><span class="pun">(</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">return</span><span class="pln"> </span><span class="kwd">NaN</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">methods</span><span class="pun">[</span><span class="pln">op</span><span class="pun">](</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">addMethod </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"> func</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">methods</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"> func</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span></pre>
</div>

<h3>
	خارطة بالكائنات
</h3>

<h3>
	فرز المستخدمين حسب أعمارهم
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	اكتب دالة <code>sortByAge(users)‎</code> تأخذ مصفوفة من الكائنات بالصفة <code>age</code> وتُرتبّها حسب أعمارهم <code>age</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_129" style="">
<span class="pln">let john </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">"John"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let pete </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">"Pete"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let mary </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">"Mary"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">28</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> pete</span><span class="pun">,</span><span class="pln"> john</span><span class="pun">,</span><span class="pln"> mary </span><span class="pun">];</span><span class="pln">

sortByAge</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln">

</span><span class="com">// [john, mary, pete]</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">arr</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">// John</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Mary</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">[</span><span class="lit">2</span><span class="pun">].</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Pete</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_131" style="">
<span class="kwd">function</span><span class="pln"> sortByAge</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  arr</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">((</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">age </span><span class="pun">&gt;</span><span class="pln"> b</span><span class="pun">.</span><span class="pln">age </span><span class="pun">?</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let john </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">"John"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let pete </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">"Pete"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let mary </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">"Mary"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">28</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> pete</span><span class="pun">,</span><span class="pln"> john</span><span class="pun">,</span><span class="pln"> mary </span><span class="pun">];</span><span class="pln">

sortByAge</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln">

</span><span class="com">// [john, mary, pete]</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">arr</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">// John</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Mary</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">[</span><span class="lit">2</span><span class="pun">].</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Pete</span></pre>
</div>

<h3>
	خلط المصفوفات
</h3>

<p class="task__importance">
	الأهمية: 3
</p>

<p>
	اكتب دالة <code>shuffle(array)‎</code> تخلط عناصر المصفوفة (أي ترتّبها عشوائيًا).
</p>

<p>
	يمكن بتكرار نداء <code>shuffle</code> إعادة العناصر بترتيب مختلف. مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_133" style="">
<span class="pln">let arr </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">

shuffle</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln">
</span><span class="com">// arr = [3, 2, 1]</span><span class="pln">

shuffle</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln">
</span><span class="com">// arr = [2, 1, 3]</span><span class="pln">

shuffle</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln">
</span><span class="com">// arr = [3, 1, 2]</span><span class="pln">
</span><span class="com">// ...</span></pre>

<p>
	يجب أن تكون جميع احتمالات ترتيب العناصر متساوية. فمثلًا يمكن إعادة ترتيب <code>[1,2,3]</code> لتكون <code>[1,2,3]</code> أو <code>[1,3,2]</code> أو <code>[3,1,2]</code> أو أو أو، واحتمال حدوث كلّ حالة متساوٍ.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		هذا هو الحل البسيط:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_135" style="">
<span class="kwd">function</span><span class="pln"> shuffle</span><span class="pun">(</span><span class="pln">array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  array</span><span class="pun">.</span><span class="pln">sort</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">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let arr </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">
shuffle</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">);</span></pre>

	<p>
		تعمل هذه الشيفرة (نوعًا ما) إذ أنّ <code>Math.random() - 0.5</code> عددٌ عشوائي ويمكن أن يكون موجبًا أم سالبًا، بذلك تُعيد دالة الفرز ترتيب العناصر عشوائيًا.
	</p>

	<p>
		ولكن ليس هذه الطريقة التي تعمل فيها دوال الفرز، إذ ليس لكلّ حالات التبديل الاحتمال نفسه. فمثلًا في الشيفرة أعلاه، تُنفّذ <code>shuffle</code> ‏1000000 مرّة وتعدّ مرّات ظهور النتائج الممكنة كلّها:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_137" style="">
<span class="kwd">function</span><span class="pln"> shuffle</span><span class="pun">(</span><span class="pln">array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  array</span><span class="pun">.</span><span class="pln">sort</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">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// نعدّ مرّات ظهور كلّ عمليات التبديل الممكنة</span><span class="pln">
let count </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="str">'123'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'132'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'213'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'231'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'321'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'312'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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">1000000</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">
  let array </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">
  shuffle</span><span class="pun">(</span><span class="pln">array</span><span class="pun">);</span><span class="pln">
  count</span><span class="pun">[</span><span class="pln">array</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="pun">}</span><span class="pln">

</span><span class="com">// نعرض عدد عمليات التبديل الممكنة</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in count</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">key</span><span class="pun">}:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">count</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]}`);</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		إليك عيّنة عن الناتج (إذ يعتمد على محرّك جافاسكربت):
	</p>

	<pre class="ipsCode">
123: 250706
132: 124425
213: 249618
231: 124880
312: 125148
321: 125223
</pre>

	<p>
		نرى تحيّز الشيفرة بوضوح شديد، إذ تظهر <code>123</code> و<code>213</code> أكثر بكثير من البقية. يختلف ناتج هذه الشيفرة حسب محرّكات جافاسكربت ولكن هذا يكفي لنقول بأنّ هذه الطريقة ليست موثوقة.
	</p>

	<p>
		ولكن لمَ لا تعمل الشيفرة؟ بشكل عام فتابِع <code>sort</code> أشبه ”بالصندوق الأسود“: نرمي فيه مصفوفة ودالة موازنة وننتظر أن تفرز لنا المصفوفة. ولكن بسبب عشوائية الموازنة يختلّ ذكاء الصندوق الأسود، وهذا الاختلال يعتمد على طريقة كتابة كلّ محرّك للشيفرة الخاصة به.
	</p>

	<p>
		ثمّة طرق أخرى أفضل لهذه المهمّة، مثل الخوارزمية <a href="https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle" rel="external nofollow">خلّاط فِشر ييتس</a> الرائعة. فكرتها هي المرور على عناصر المصفوفة بالعكس وتبديل كلّ واحد بآخر قبله عشوائيًا:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_140" style="">
<span class="kwd">function</span><span class="pln"> shuffle</span><span class="pun">(</span><span class="pln">array</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="pln">let i </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</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">
    let j </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="pln">i </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">// ‫رقم عشوائي من 0 إلى i</span><span class="pln">

    </span><span class="com">// let t = array[i]; array[i] = array[j]; array[j] = t</span><span class="pln">
    </span><span class="pun">[</span><span class="pln">array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">],</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">array</span><span class="pun">[</span><span class="pln">j</span><span class="pun">],</span><span class="pln"> array</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>
		بدلنا بالمثال هذا العنصرين array‎ و array[j]‎ وذلك نستعمل صياغة ”الإسناد بالتفكيك" وستجد تفاصيل أكثر عن هذه الصياغة في فصول لاحقة.
	</p>

	<p>
		لنختبر الطريقة هذه بنفس ما اختبرنا تلك:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_142" style="">
<span class="kwd">function</span><span class="pln"> shuffle</span><span class="pun">(</span><span class="pln">array</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="pln">let i </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</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">
    let j </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="pln">i </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">array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">],</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">array</span><span class="pun">[</span><span class="pln">j</span><span class="pun">],</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]];</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// نعدّ مرّات ظهور كلّ عمليات التبديل الممكنة</span><span class="pln">
let count </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="str">'123'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'132'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'213'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'231'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'321'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'312'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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">1000000</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">
  let array </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">
  shuffle</span><span class="pun">(</span><span class="pln">array</span><span class="pun">);</span><span class="pln">
  count</span><span class="pun">[</span><span class="pln">array</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="pun">}</span><span class="pln">

</span><span class="com">// نعرض عدد عمليات التبديل الممكنة</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in count</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">key</span><span class="pun">}:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">count</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]}`);</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		عيّنة عن الناتج:
	</p>

	<pre class="ipsCode">
123: 166693
132: 166647
213: 166628
231: 167517
312: 166199
321: 166316
</pre>

	<p>
		الآن كل شيء سليم: لكلّ عمليات التبديل ذات الاحتمال. كما أنّ خوارزمية ”فِشر ييتس“ أفضل من ناحية الأداء إذ ليس علينا تخصيص الموارد لعملية ”الفرز“.
	</p>
</div>

<h3>
	ما متوسّط الأعمار؟
</h3>

<p class="task__importance">
	الأهمية: 4
</p>

<p>
	اكتب دالة <code>getAverageAge(users)‎</code> تأخذ مصفوفة من كائنات لها الصفة <code>age</code> وتُعيد متوسّط الأعمار.
</p>

<p>
	معادلة المتوسّط: <code>‎(age1 + age2 + ... + ageN) / N</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_144" style="">
<span class="pln">let john </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">"John"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let pete </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">"Pete"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let mary </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">"Mary"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">29</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> john</span><span class="pun">,</span><span class="pln"> pete</span><span class="pun">,</span><span class="pln"> mary </span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> getAverageAge</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// (25 + 30 + 29) / 3 = 28</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_146" style="">
<span class="kwd">function</span><span class="pln"> getAverageAge</span><span class="pun">(</span><span class="pln">users</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"> users</span><span class="pun">.</span><span class="pln">reduce</span><span class="pun">((</span><span class="pln">prev</span><span class="pun">,</span><span class="pln"> user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> prev </span><span class="pun">+</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">age</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"> users</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let john </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">"John"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let pete </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">"Pete"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let mary </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">"Mary"</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">29</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> john</span><span class="pun">,</span><span class="pln"> pete</span><span class="pun">,</span><span class="pln"> mary </span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> getAverageAge</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 28</span></pre>
</div>

<h3>
	ترشيح العناصر الفريدة في المصفوفة
</h3>

<p class="task__importance">
	الأهمية: 4
</p>

<p>
	لمّا أنّ <code>arr</code> مصفوفة، أنشِئ دالة <code>unique(arr)‎</code> تُعيد مصفوفة فيها عناصر <code>arr</code> غير مكرّرة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_148" style="">
<span class="kwd">function</span><span class="pln"> unique</span><span class="pun">(</span><span class="pln">arr</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">

let strings </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">":-O"</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> unique</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hare, Krishna, :-O</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		ما سنفعل هو المرور على عناصر المصفوفة:
	</p>

	<ul>
<li>
			سنفحص كلّ عنصر ونرى إن كان في المصفوفة الناتجة.
		</li>
		<li>
			إن كان كذلك… نُهمله، وإن لم يكن، نُضيفه إلى المصفوفة.
		</li>
	</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1764_150" style="">
<span class="kwd">function</span><span class="pln"> unique</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let result </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="pln">let str of arr</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">result</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="pln">str</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">push</span><span class="pun">(</span><span class="pln">str</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"> result</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let strings </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Krishna"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hare"</span><span class="pun">,</span><span class="pln"> </span><span class="str">":-O"</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> unique</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hare, Krishna, :-O</span></pre>

	<p>
		صحيح أنّ الكود يعمل، إلّا أنّ فيه مشكلة أداء محتملة. خلف الكواليس، يمرّ التابِع <code>result.includes(str)‎</code> على المصفوفة <code>result</code> ويقارن كلّ عنصر مع <code>str</code> ليجد المطابقة المنشودة. لذا لو كان في <code>result</code> مئة <code>100</code> عنصر وما من أيّ مطابقة مع <code>str</code>، فعليها المرور على جُلّ <code>result</code> وإجراء <code>100</code> حالة مقارنة كاملة. ولو كانت <code>result</code> كبيرة مثل <code>10000</code> فيعني ذلك <code>10000</code> حالة مقارنة.
	</p>

	<p>
		إلى هنا لا مشكلة، لأنّ محرّكات جافاسكربت سريعة جدًا، والمرور على <code>1000</code> عنصر في المصفوفة يحدث في بضعة ميكروثوان. ولكنّا هنا في حلقة <code>for</code> نُجري هذه الشروط لكلّ عنصر من <code>arr</code>. فإن كانت <code>arr.length</code> تساوي <code>10000</code> فيعني أنّا سنُجري <code>10000*10000</code> = مئة مليون حالة مقارنة. كثير جدًا.
	</p>

	<p>
		إذًا، فهذا الحل ينفع للمصفوفات الصغيرة فقط. سنرى لاحقًا في الفصل <map-set> كيف نحسّن هذا الكود.</map-set></p>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/array-methods" rel="external nofollow">Array methods</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a><em><em> </em></em>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%83%D8%B1%D9%91%D9%8E%D8%B1%D8%A9-iterables-r820/" rel="">الكائنات المكرَّرة (Iterables)</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-arrays-r818/" rel="">المصفوفات (arrays)</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">819</guid><pubDate>Sun, 23 Feb 2020 14:21:40 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x635;&#x641;&#x648;&#x641;&#x627;&#x62A; (arrays) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#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-arrays-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r818/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/35.jpg.66562ba26cd48f11093acf20a44a6788.jpg" /></p>

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

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

<p>
	توجد بنية بيانات أخرى باسم <code>Array</code> (ندعو هذا النوع بالمصفوفة) وهي تتيح لنا تخزين مجموعات العناصر مرتّبةً.
</p>

<h2>
	التصريح
</h2>

<p>
	توجد صياغتان اثنتان لإنشاء مصفوفة فارغة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_7" style="">
<span class="pln">let arr </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="pln">
let arr </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_73_9" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Plum"</span><span class="pun">];</span></pre>

<p>
	لاحظ أنّ عناصر المصفوفات مرقّمة (مُفهرسة) بدءًا من الرقم صفر. ويمكننا أن نأخذ عنصرًا منها بكتابة ترتيبه في أقواس معقوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_11" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Plum"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits</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="com">// Apple/تفاحة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> fruits</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"> </span><span class="com">// Orange/برتقالة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> fruits</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Plum/برقوق</span></pre>

<p>
	يمكن أيضًا تعويض أحد العناصر بأخرى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_18" style="">
<span class="pln">fruits</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Pear'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫ ["Apple", "Orange", "Pear"]</span></pre>

<p>
	…أو إضافة أخرى جديدة إلى المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_16" style="">
<span class="pln">fruits</span><span class="pun">[</span><span class="lit">3</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Lemon'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ["Apple", "Orange", "Pear", "Lemon"]</span></pre>

<p>
	نعرف باستعمال التابع <code>length</code> إجمالي العناصر في المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_20" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Plum"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits</span><span class="pun">.</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3</span></pre>

<p>
	يمكننا أيضًا استعمال <code>alert</code> لعرض المصفوفة كاملةً.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_22" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Plum"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Apple,Orange,Plum</span></pre>

<p>
	كما يمكن للمصفوفات تخزين أيّ نوع من البيانات. مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_24" style="">
<span class="com">// قيم مختلفة الأنواع</span><span class="pln">
let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="str">'Apple'</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">'John'</span><span class="pln"> </span><span class="pun">},</span><span class="pln"> </span><span class="kwd">true</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"> 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"> </span><span class="pun">];</span><span class="pln">

</span><span class="com">// خُذ الكائن ذا الفهرس 1 ثمّ اعرض اسمه</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">name </span><span class="pun">);</span><span class="pln"> </span><span class="com">// John</span><span class="pln">

</span><span class="com">// خُذ الدالة في الفهرس 3 ثمّ شغّلها</span><span class="pln">
arr</span><span class="pun">[</span><span class="lit">3</span><span class="pun">]();</span><span class="pln"> </span><span class="com">// hello</span></pre>

<p>
	<strong>الفاصلة نهاية الجملة</strong> كما الكائنات، يمكن أن نُنهي عناصر المصفوفات بفاصلة <code>,</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_26" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="str">"Apple"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Plum"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">];</span></pre>

<p>
	يُسهّل أسلوب الكتابة «بالفاصلة نهاية الجملة» إضافة العناصر وإزالتها، إذ أن الأسطر البرمجية كلها تصير متشابهة.
</p>

<h2>
	توابِع الدفع والجلب
</h2>

<p>
	من بين أنواع المصفوفات، تُعدّ <a href="https://en.wikipedia.org/wiki/Queue_(abstract_data_type)" rel="external nofollow">الطوابير</a> أكثرها استعمالًا. تعني الصفوف (في <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>) تجميعات العناصر المرتّبة والتي تدعم العمليتين هاتين:
</p>

<ul>
<li>
		الدفع <code>push</code>: يُضيف عنصرًا نهاية الصفّ
	</li>
	<li>
		الأخذ <code>shift</code>: يأخذ عنصرًا من بداية الصفّ، فيتحرّك الصفّ ويصير العنصر الثاني هو الأول فيه.
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="33716" href="https://academy.hsoub.com/uploads/monthly_2020_02/queue.png.f7cfa5d5ce724963fc1ca82d59902877.png" rel=""><img alt="queue.png" class="ipsImage ipsImage_thumbnailed" data-fileid="33716" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/queue.png.f7cfa5d5ce724963fc1ca82d59902877.png"></a>
</p>

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

<p>
	هناك طريقة أخرى لاستعمال المصفوفات، وهي بنية البيانات بالاسم «<a href="https://en.wikipedia.org/wiki/Stack_(abstract_data_type)" rel="external nofollow">كومة</a>».
</p>

<p>
	تدعم الأكوام عمليتين أيضًا:
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="33717" href="https://academy.hsoub.com/uploads/monthly_2020_02/stack.png.b1947405105a887079827a83892c5f65.png" rel=""><img alt="stack.png" class="ipsImage ipsImage_thumbnailed" data-fileid="33717" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/stack.png.b1947405105a887079827a83892c5f65.png"></a>
</p>

<p>
	في الأكوام، آخر عنصر ندفعه إليها يكون أوّل من يُأخذ، ويسمّى هذا بمبدأ «آخر من يدخل أول من يخرج» (<strong>L</strong>ast-<strong>I</strong>n-<strong>F</strong>irst-<strong>O</strong>ut). أمّا في الطوابير، فهي «أول من يدخل أول من يخرج» (<strong>F</strong>irst-<strong>I</strong>n-<strong>F</strong>irst-<strong>O</strong>ut).
</p>

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

<p>
	تُسمّى بنية البيانات هذه (في <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>) باسم «<a href="https://en.wikipedia.org/wiki/Double-ended_queue" rel="external nofollow">الطوابير ذات الطرفين</a>».
</p>

<p>
	<strong>التوابع التي تؤثّر على نهاية المصفوفة:</strong>
</p>

<ul>
<li>
		<p>
			<code>pop</code>: يستخرج آخر عنصر من المصفوفة ويُعيده:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_28" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Pear"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits</span><span class="pun">.</span><span class="pln">pop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫أزِل «Pear» بتنبيه عبر الدالة alert</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Apple, Orange</span></pre>

		<p>
			 
		</p>
	</li>
	<li>
		<p>
			<code>push</code>: يُضيف العنصر إلى آخر المصفوفة:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_30" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">];</span><span class="pln">

fruits</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"Pear"</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Apple, Orange, Pear</span></pre>

		<p>
			 
		</p>
	</li>
</ul>
<p>
	باستدعاء <code>fruits.push(...)‎</code> كأنّما استدعيت <code>fruits[fruits.length] = ...‎</code>.
</p>

<p>
	<strong>التوابِع التي تؤثّر على بداية المصفوفة:</strong>
</p>

<ul>
<li>
		<p>
			<code>shift</code>: يستخرج أوّل عنصر من المصفوفة وتُعيده:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_32" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Pear"</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits</span><span class="pun">.</span><span class="pln">shift</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫أزِل التفاحة واعرضها بِ‍ alert</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Orange, Pear</span></pre>

		<p>
			 
		</p>
	</li>
	<li>
		<p>
			<code>unshift</code>: يُضيف العنصر إلى أوّل المصفوفة:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_34" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Pear"</span><span class="pun">];</span><span class="pln">

fruits</span><span class="pun">.</span><span class="pln">unshift</span><span class="pun">(</span><span class="str">'Apple'</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Apple, Orange, Pear</span></pre>

		<p>
			 
		</p>
	</li>
</ul>
<p>
	يمكنك أيضًا إضافة أكثر من عنصر في استدعاء واحد من <code>push</code> و<code>unshift</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_36" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apple"</span><span class="pun">];</span><span class="pln">

fruits</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Peach"</span><span class="pun">);</span><span class="pln">
fruits</span><span class="pun">.</span><span class="pln">unshift</span><span class="pun">(</span><span class="str">"Pineapple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Lemon"</span><span class="pun">);</span><span class="pln">

</span><span class="com">// ["Pineapple", "Lemon", "Apple", "Orange", "Peach"]</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> fruits </span><span class="pun">);</span></pre>

<h2>
	داخليًا وخلف الكواليس
</h2>

<p>
	المصفوفات هي كائنات، كائنات من نوع خاص. القوسان المعقوفان المستعملان للدخول إلى الخاصيات <code>arr[0]‎</code> هما فعليًا جزء من صياغة الكائنات. داخليًا، لا يفرق ذاك عن <code>obj[key]‎</code> (إذ <code>arr</code> هو الكائن والأرقام تلك مفاتيح).
</p>

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

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

<p>
	فمثلًا، عند نسخها تُنسخ بالمرجع (By reference):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_38" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Banana"</span><span class="pun">]</span><span class="pln">

let arr </span><span class="pun">=</span><span class="pln"> fruits</span><span class="pun">;</span><span class="pln"> </span><span class="com">// انسخها بالمرجع (متغيران اثنان يُشيران إلى نفس المصفوفة)‏</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">===</span><span class="pln"> fruits </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">

arr</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"Pear"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫عدّل المصفوفة «بالمرجع»</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits </span><span class="pun">);</span><span class="pln"> </span><span class="com">// صاروا الآن عنصرين: ‫Banana, Pear</span></pre>

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

<p>
	ولكن، لو لم نعمل مع المصفوفة على أنّها «تجميعة مرتّبة» بل وكأنّها كائن مثل غيرها، فسينهار هذا كله.
</p>

<p>
	يمكننا (تقنيًا) كتابة هذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_40" style="">
<span class="com">// نصنع مصفوفة</span><span class="pln">
let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln"> 

</span><span class="com">// نُسند خاصيةً لها فهرس أكبر من طول المصفوفة بكثير</span><span class="pln">
fruits</span><span class="pun">[</span><span class="lit">99999</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln"> 

</span><span class="com">// نُنشئ خاصيةً لها أيّ اسم</span><span class="pln">
fruits</span><span class="pun">.</span><span class="pln">age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">25</span><span class="pun">;</span><span class="pln"> </span></pre>

<p>
	أجل، يمكننا فعل هذا، فالمصفوفات في أساسها كائنات، ويمكننا إضافة ما نريد من خاصيات لها.
</p>

<p>
	ولكن المحرّك هنا سيرى بأنّا نُعامل المصفوفة معاملة الكائن العادي. وبهذا -في هذه الحالة- لا تنفع أنواع التحسين المخصّصة للكائنات، وسيُعطّلها المحرّك، وتضيع كل فوائد المصفوفات.
</p>

<p>
	هذه طرائق يمكنك فيها إساءة استعمال المصفوفات:
</p>

<ul>
<li>
		إضافة خاصيات ليست عددية مثل <code>arr.test = 5</code>.
	</li>
	<li>
		الفراغات، أي تُضيف <code>arr[0]‎</code> وبعدها <code>arr[1000]‎</code> (دون عناصر بينها).
	</li>
	<li>
		ملء المصفوفة بالعكس، أي <code>arr[1000]‎</code> ثم <code>arr[999]‎</code> وهكذا.
	</li>
</ul>
<p>
	نرجوك هنا أن تعتبر المصفوفات بنًى خاصّة تتعامل مع <em>البيانات المرتّبة</em>، فهي تقدّم لك توابِع خاصّة لهذا بالذات. يتغيّر تعامل محرّكات جافاسكربت حين تتعامل مع المصفوفات، فتعمل مع البيانات المرتّبة المتتابعة، فمن فضلك استعمِلها بهذه الطريقة. لو أردت مفاتيح لا عددية، أو مثلما في الحالات الثلاث أعلاه، فغالبًا لا تكون المصفوفة ما تبحث عنه، بل الكائنات العادية <code>{}</code>.
</p>

<h2>
	الأداء
</h2>

<p>
	يعمل التابِعان <code>push/pop</code> بسرعة، بينما <code>shift/unshift</code> بطيئان.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="33715" href="https://academy.hsoub.com/uploads/monthly_2020_02/array-speed.png.0348f45a85716307ae098b280dd93498.png" rel=""><img alt="array-speed.png" class="ipsImage ipsImage_thumbnailed" data-fileid="33715" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/array-speed.png.0348f45a85716307ae098b280dd93498.png"></a>
</p>

<p>
	لماذا يكون التعامل مع نهاية المصفوفة أسرع من التعامل مع بدايتها؟ لنأخذ نظرة عمًا يحدث أثناء تنفيذ الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_44" style="">
<span class="com">// خُذ عنصرًا واحدًا من الأوّل</span><span class="pln">
fruits</span><span class="pun">.</span><span class="pln">shift</span><span class="pun">();</span><span class="pln"> </span></pre>

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

<p>
	ما تفعله عملية <code>shift</code> هي ثلاث أمور:
</p>

<ol>
<li>
		إزالة العنصر ذا الفهرس <code>0</code>.
	</li>
	<li>
		تحريك كل العناصر الأخرى إلى يسار المصفوفة، وإعادة ترقيمها من الفهرس رقم <code>1</code> إلى <code>0</code>، ومن <code>2</code> إلى <code>1</code>، وهكذا.
	</li>
	<li>
		تحديث خاصية الطول <code>length</code>.
	</li>
</ol>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="33714" href="https://academy.hsoub.com/uploads/monthly_2020_02/array-shift.png.a7d9dd51620beba2a6b1442de9130795.png" rel=""><img alt="array-shift.png" class="ipsImage ipsImage_thumbnailed" data-fileid="33714" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/array-shift.png.a7d9dd51620beba2a6b1442de9130795.png"></a>
</p>

<p>
	<strong>زِد العناصر في المصفوفات، تزيد الوقت اللازم لتحريكها، وتزيد عدد العمليات داخل الذاكرة.</strong>
</p>

<p>
	مثل <code>shift</code>، تفعل <code>unshift</code> نفس الأمور: فلنُضيف عنصرًا إلى بداية المصفوفة، علينا أولًا تحريك كل العناصر إلى اليمين، أي نزيد فهارسها كلها.
</p>

<p>
	وماذا عن <code>push/pop</code>؟ ليس عليها تحريك أيّ عنصر. فلاستخراج عنصر من النهاية، يمحي التابِع <code>pop</code> الفهرس ويعدّل الطول <code>length</code> فيقصّره.
</p>

<p>
	إجراءات عملية <code>pop</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_46" style="">
<span class="com">// خُذ عنصرًا واحدًا من الآخر</span><span class="pln">
fruits</span><span class="pun">.</span><span class="pln">pop</span><span class="pun">();</span><span class="pln"> </span></pre>

<p>
	 
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="33713" href="https://academy.hsoub.com/uploads/monthly_2020_02/array-pop.png.4cfb9a1b9d753c1061e82d5b88077314.png" rel=""><img alt="array-pop.png" class="ipsImage ipsImage_thumbnailed" data-fileid="33713" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/array-pop.png.4cfb9a1b9d753c1061e82d5b88077314.png"></a>
</p>

<p>
	<strong>لا تحتاج عملية <code>pop</code> إلى تحريك ولا مقدار ذرة، لأنّ العناصر تبقى كما هي مع فهارسها. لهذا السبب سرعتها تفوق سرعة البرق، أي أقصى سرعة ممكنة.</strong>
</p>

<p>
	ذات الأمر للتابِع <code>push</code>.
</p>

<h2>
	الحلقات
</h2>

<p>
	هذه إحدى أقدم الطرق للمرور على عناصر المصفوفات، استعمال حلقة <code>for</code> بالمرور على فهارس المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_48" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Pear"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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"> arr</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> arr</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>
	ولكن المصفوفات تسمح بطريقة أخرى للمرور عليها، <code>for..of</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_50" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Plum"</span><span class="pun">];</span><span class="pln">

</span><span class="com">// المرور على عناصر المصفوفة</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let fruit of fruits</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> fruit </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	طالما المصفوفات كائنات، فيمكننا (نظريًا) استعمال <code>for..in</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_52" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Pear"</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Apple, Orange, Pear</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ولكن الواقع أنّ الطريقة هذه سيئة، ففيها عدد من المشاكل:
</p>

<ol>
<li>
		تمرّ الحلقة <code>for..in</code> على <em>كل الخاصيات</em> مجتمعةً، وليس العددية منها فقط. توجد في المتصفّح وغيرها من بيئات كائنات «شبيهة بالمصفوفات». أي أن لها خاصية الطول <code>length</code> وخاصيات الفهارس، ولكن لها أيضًا توابِع وخاصيات لا عددية أخرى لا نحتاجها أغلب الأحيان، إلّا أنّ حلقة <code>for..in</code> ستمرّ عليها هي أيضًا. لذا لو اضطررت للعمل مع الكائنات الشبيهة بالمصفوفات، فهذه الخاصيات «الأخرى» ستتسبّب بالمتاعب بلا شك.
	</li>
	<li>
		أداء حلقة <code>for..in</code> يكون بالنحو الأمثل على الكائنات العامة لا المصفوفات، ولهذا سيكون أبطأ 10 أو 100 مرة. طبعًا فالأداء سريع جدًا مع ذلك. هذه السرعة الإضافية ستنفع غالبًا في الحالات الحرجة (أي حين يجب أن يكون تنفيذ الحلقة بأسرع وقت ممكن). مع ذلك، الحرس واجب والاهتمام بهذا الاختلاف مهم.
	</li>
</ol>
<p>
	لكن في أغلب الأحيان، استعمال <code>for..in</code> للمصفوفات فكرة سيئة.
</p>

<h2>
	كلمتان حول «الطول»
</h2>

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

<p>
	فمثلًا، لو كان لعنصر واحد فهرس كبير، فسيكون الطول كبيرًا أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_56" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">
fruits</span><span class="pun">[</span><span class="lit">123</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Apple"</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits</span><span class="pun">.</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 124</span></pre>

<p>
	لكنّنا لا نستعمل المصفوفات هكذا. سجّلها عندك.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_62" style="">
<span class="pln">let arr </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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span><span class="pln">

</span><span class="com">// نبتر المصفوفة ونُبقي عنصرين فقط</span><span class="pln">
arr</span><span class="pun">.</span><span class="pln">length </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln"> 
alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// [1, 2]</span><span class="pln">

</span><span class="com">// نُعيد الطول الذي كان في الأوّل</span><span class="pln">
arr</span><span class="pun">.</span><span class="pln">length </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln"> 

</span><span class="com">// undefined القيم المبتورة لا تعود، وإنما تصبح</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">[</span><span class="lit">3</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span></pre>

<p>
	إذًا، فالطريقة الأسهل والأبسط لمسح المصفوفة هي: <code>arr.length = 0;‎</code>.
</p>

<h2>
	new Array()‎
</h2>

<p>
	هناك صياغة أخرى يمكن استعمالها لإنشاء المصفوفات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_64" style="">
<span class="pln">let arr </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="str">"Apple"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Pear"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"etc"</span><span class="pun">);</span></pre>

<p>
	ولكنّها نادرًا ما تُستعمل، فالأقواس المعقوفة <code>[]</code> أقصر. كما وأنّ هذه الطريقة تقدّم ميزة… مخادعة، إن صحّ التعبير.
</p>

<p>
	إن استدعيت <code>new Array</code> وفيها مُعامل واحد فقط (عددي)، فستُنشأ مصفوفة <em>لا عناصر فيها، ولكن بالطول المحدّد</em>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_66" style="">
<span class="pln">let arr </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">2</span><span class="pun">);</span><span class="pln"> </span><span class="com">// هل ستكون المصفوفة [2]؟</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr</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="com">//‫غير معرّفة! ليس فيها عناصر.</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// طولها 2</span></pre>

<p>
	في هذا الشيفرة، كل عناصر <code>new Array(number)‎</code> لها القيمة <code>undefined</code>. ولهذا نستعمل الأقواس المعقوفة غالبًا، لنتجنّب هذه المفاجئات السارّة، إلّا لو كنت تعي حقًا ما تفعله.
</p>

<h2>
	المصفوفات متعدّدة الأبعاد
</h2>

<p>
	يمكن أن تكون عناصر المصفوفات مصفوفات أخرى أيضًا. نستغلّ هذه الميزة فنعمل مصفوفات متعدّدة الأبعاد لتخزين المصفوفات الرياضية مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_68" style="">
<span class="pln">let matrix </span><span class="pun">=</span><span class="pln"> </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="pun">[</span><span class="lit">4</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">6</span><span class="pun">],</span><span class="pln">
  </span><span class="pun">[</span><span class="lit">7</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">9</span><span class="pun">]</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> matrix</span><span class="pun">[</span><span class="lit">1</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"> </span><span class="com">// ‫5، العنصر في الوسط</span></pre>

<h2>
	تحويل المصفوفات إلى سلاسل نصية
</h2>

<p>
	تُنفّذ المصفوفات تابِع <code>toString</code> خاصّ بها، فيُعيد قائمة من العناصر مفصولة بفواصل. خُذ هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_70" style="">
<span class="pln">let arr </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">

alert</span><span class="pun">(</span><span class="pln"> arr </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1,2,3</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">String</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> </span><span class="str">'1,2,3'</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	جرّب هذه، أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_72" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">[]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "1"</span><span class="pln">
alert</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"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "11"</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "1,21"</span></pre>

<p>
	ليس للمصفوفات <code>Symbol.toPrimitive</code> ولا دالة <code>valueOf</code>، بل تُنفّذ التحويل <code>toString</code> فقط لا غير. هكذا تصير <code>[]</code> سلسلة نصية فارغة، و<code>[1]</code> تصير <code>"1"</code> و<code>[1,2]</code> تصير <code>"1,2"</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_74" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">""</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "1"</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"1"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "11"</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"1,2"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "1,21"</span></pre>

<h2>
	ملخص
</h2>

<p>
	المصفوفات نوع خاصّ من الكائنات، وهي مخصّصة لتخزين البيانات عناصر مرتّبة، كما وإدارتها أيضًا.
</p>

<ul>
<li>
		<p>
			التصريح
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_76" style="">
<span class="com">// الأقواس المعقوفة (طبيعية)‏</span><span class="pln">
let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">item1</span><span class="pun">,</span><span class="pln"> item2</span><span class="pun">...];</span><span class="pln">

</span><span class="com">// ‫new Array (نادرة جدًا)</span><span class="pln">
let arr </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="pln">item1</span><span class="pun">,</span><span class="pln"> item2</span><span class="pun">...);</span></pre>

		<p>
			 
		</p>
	</li>
</ul>
<p>
	باستدعاء <code>new Array(number)‎</code> تُنشئ مصفوفة بالطول المحدّد، ولكن بلا أيّ عنصر.
</p>

<ul>
<li>
		خاصية الطول <code>length</code> هي طول المصفوفة، أو للدّقة، آخر فهرس عددي زائدًا واحد. التوابِع المختلفة على المصفوفات تعدّل هذه الخاصية تلقائيًا.
	</li>
	<li>
		إن قصّرنا خاصية <code>length</code> يدويًا، فنحن نبتر المصفوفة حسب القيمة الجديدة.
	</li>
</ul>
<p>
	يمكننا استعمال المصفوفة كما الصفوف ذات الطرفين، بالعمليات الآتية:
</p>

<ul>
<li>
		<code>push(...items)‎</code>: تُضيف <code>items</code> إلى النهاية.
	</li>
	<li>
		<code>pop()‎</code>: تُزيل العنصر من النهاية وتُعيده.
	</li>
	<li>
		<code>shift()‎</code>: تُزيل العنصر من البداية وتُعيده.
	</li>
	<li>
		<code>unshift(...items)‎</code>: تُضيف <code>items</code> إلى البداية.
	</li>
</ul>
<p>
	لتمرّ على عناصر المصفوفة:
</p>

<ul>
<li>
		<code>for (let i=0; i&lt;arr.length; i++)‎</code> -- تتنفّذ بسرعة، ومتوافقة مع المتصفحات القديمة.
	</li>
	<li>
		<code>for (let item of arr)‎</code> -- الصياغة الحديثة للعناصر فقط.
	</li>
	<li>
		<code>for (let i in arr)‎</code> -- إيّاك واستعمالها.
	</li>
</ul>
<p>
	سنرجع إلى المصفوفات لاحقًا ونتعلّم توابِع أخرى لإضافة العناصر وإزالتها واستخراجها، كما وترتيب المصفوفات. هذا كله في الفصل التالي، توابع المصفوفات.
</p>

<h2>
	تمارين
</h2>

<h3>
	هل تُنسخ المصفوفات؟
</h3>

<p class="task__importance">
	<em>الأهمية: 3</em>
</p>

<p>
	ما ناتج هذه الشيفرة؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_78" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apples"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Pear"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">];</span><span class="pln">

</span><span class="com">// ‫ادفع عنصرًا جديدًا داخل «النسخة»</span><span class="pln">
let shoppingCart </span><span class="pun">=</span><span class="pln"> fruits</span><span class="pun">;</span><span class="pln">
shoppingCart</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"Banana"</span><span class="pun">);</span><span class="pln">

</span><span class="com">// ماذا في ‫fruits؟</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> fruits</span><span class="pun">.</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ?</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		الناتج هو <code>4</code>:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_80" style="">
<span class="pln">let fruits </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Apples"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Pear"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Orange"</span><span class="pun">];</span><span class="pln">

let shoppingCart </span><span class="pun">=</span><span class="pln"> fruits</span><span class="pun">;</span><span class="pln">

shoppingCart</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"Banana"</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> fruits</span><span class="pun">.</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 4</span></pre>

	<p>
		هذا لأنّ المصفوفات كائنات. فكِلا <code>shoppingCart</code> و<code>fruits</code> يُشيران إلى نفس المصفوفة ذاتها.
	</p>
</div>

<h3>
	العمليات على المصفوفات
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	فلنجرّب خمس عمليات على المصفوفات.
</p>

<ol>
<li>
		أنشِئ مصفوفة باسم <code>styles</code> تحوي العنصرين «Jazz» و«Blues».
	</li>
	<li>
		أضِف «Rock-n-Roll» إلى نهايتها.
	</li>
	<li>
		استبدِل القيمة في الوسط بالقيمة «Classics». يجب أن تعمل الشيفرة الذي ستكتبه ليجد القيمة في الوسط مع أيّ مصفوفة كانت لو كان طولها عدد فردي.
	</li>
	<li>
		أزِل القيمة الأولى من المصفوفة واعرضها.
	</li>
	<li>
		أضِف «Rap» و«Reggae» إلى بداية المصفوفة.
	</li>
</ol>
<p>
	المصفوفة خلال العمليات هذه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_82" style="">
<span class="typ">Jazz</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Blues</span><span class="pln">
</span><span class="typ">Jazz</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Blues</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Rock</span><span class="pun">-</span><span class="pln">n</span><span class="pun">-</span><span class="typ">Roll</span><span class="pln">
</span><span class="typ">Jazz</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Classics</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Rock</span><span class="pun">-</span><span class="pln">n</span><span class="pun">-</span><span class="typ">Roll</span><span class="pln">
</span><span class="typ">Classics</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Rock</span><span class="pun">-</span><span class="pln">n</span><span class="pun">-</span><span class="typ">Roll</span><span class="pln">
</span><span class="typ">Rap</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Reggae</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Classics</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Rock</span><span class="pun">-</span><span class="pln">n</span><span class="pun">-</span><span class="typ">Roll</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_84" style="">
<span class="pln">let styles </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"Jazz"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Blues"</span><span class="pun">];</span><span class="pln">
styles</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"Rock-n-Roll"</span><span class="pun">);</span><span class="pln">
styles</span><span class="pun">[</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">((</span><span class="pln">styles</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Classics"</span><span class="pun">;</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> styles</span><span class="pun">.</span><span class="pln">shift</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
styles</span><span class="pun">.</span><span class="pln">unshift</span><span class="pun">(</span><span class="str">"Rap"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Reggae"</span><span class="pun">);</span></pre>
</div>

<h3>
	النداء داخل سياق المصفوفة
</h3>

<p class="task__importance">
	<em>الأهمية: 5</em>
</p>

<p>
	ما الناتج؟ لماذا؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_86" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"a"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"b"</span><span class="pun">];</span><span class="pln">

arr</span><span class="pun">.</span><span class="pln">push</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">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

arr</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]();</span><span class="pln"> </span><span class="com">// ?</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		من ناحية الصياغة، فالاستدعاء <code>arr[2]()‎</code> هو نفسه النداء القديم <code>obj[method]()‎</code>، فبدل <code>obj</code> هناك <code>arr</code>، وبدل <code>method</code> هناك <code>2</code>.
	</p>

	<p>
		إذًا فما أمامنا هو نداء الدالة <code>arr[2]‎</code> وكأنّها تابِع لكائن. وبالطبيعة، فهي تستلم <code>this</code> الذي يُشير إلى الكائن <code>arr</code>وتكتب المصفوفة ناتجًا:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_88" style="">
<span class="pln">let arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"a"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"b"</span><span class="pun">];</span><span class="pln">

arr</span><span class="pun">.</span><span class="pln">push</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">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

arr</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]();</span><span class="pln"> </span><span class="com">// "a","b",function</span></pre>

	<p>
		للمصفوفة ثلاث قيم: الاثنتين من البداية، مع الدالة.
	</p>
</div>

<h3>
	جمع الأعداد المُدخلة
</h3>

<p class="task__importance">
	<em>الأهمية: 4</em>
</p>

<p>
	اكتب دالة <code>sumInput()‎</code> تؤدّي الآتي:
</p>

<ul>
<li>
		طلب القيم من المستخدم باستعمال <code>prompt</code> وتخزينها في مصفوفة.
	</li>
	<li>
		أن ينتهي الطلب لو أدخل المستخدم قيمة غير عددية، أو سلسلة نصية فارغة، أو ضغطَ «ألغِ».
	</li>
	<li>
		حساب مجموع عناصر المصفوفة وإعادتها.
	</li>
</ul>
<p>
	ملاحظة: الصفر <code>0</code> عدد مسموح، لذا لا تُوقف الطلب لو رأيته.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		انتبه هنا على التفصيل الصغير في الحل، صغير ولكن مهمّ: لا يمكننا تحويل قيمة المتغير <code>value</code> إلى عدد <em>مباشرةً</em> بعد <code>prompt</code>، لأنّه بعدما نُجري <code>value = +value</code>، لن نفرّق بين السلسلة النصية الفارغة (أي علينا إيقاف الطلب) من الصفر (قيمة صالحة). عوض ذلك نؤجّل ذلك لما بعد.
	</p>

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

  let numbers </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="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    let value </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"A number please?"</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">// هل نلغي الطلب؟</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value </span><span class="pun">===</span><span class="pln"> </span><span class="str">""</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> value </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isFinite</span><span class="pun">(</span><span class="pln">value</span><span class="pun">))</span><span class="pln"> </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">

    numbers</span><span class="pun">.</span><span class="pln">push</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">

  let sum </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">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let number of numbers</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sum </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"> sum</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> sumInput</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span></pre>
</div>

<h3>
	أكبر مصفوفة فرعية
</h3>

<p class="task__importance">
	<em>الأهمية: 2</em>
</p>

<p>
	البيانات المُدخلة هي مصفوفة من الأعداد، مثل <code>arr = [1, -2, 3, 4, -9, 6]‎</code>. والمهمة هي: البحث عن مصفوفة فرعية متتابعة في <code>arr</code> لها أكبر ناتج جمع.
</p>

<p>
	اكتب دالة <code>getMaxSubSum(arr)‎</code> لتُعيد ذلك الناتج.
</p>

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

<pre class="ipsCode" id="ips_uid_73_96">
getMaxSubSum([-1, 2, 3, -9]) = 5 (مجموع 2+3)
getMaxSubSum([2, -1, 2, 3, -9]) = 6 (مجموع 2+(-1)+2+3)
getMaxSubSum([-1, 2, 3, -9, 11]) = 11 ‫(وهكذا...)
getMaxSubSum([-2, -1, 1, 2]) = 3
getMaxSubSum([100, -9, 2, -3, 5]) = 100
getMaxSubSum([1, 2, 3]) = 6 (نأخذها كلها)</pre>

<p>
	إن كانت القيم كلها سالبة فيعني هذا ألا نأخذ شيئا (المصفوفة الفرعية فارغة)، وبهذا يكون الناتج صفرًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_94" style="">
<span class="pln">getMaxSubSum</span><span class="pun">([-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">3</span><span class="pun">])</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span></pre>

<p>
	يُحبّذ لو تفكّر -رجاءً- بحلّ سريع: <a href="https://en.wikipedia.org/wiki/Big_O_notation" rel="external nofollow">O(n<sup>2</sup>)</a> أو حتّى O(n) لو أمكنك.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<ul>
<li>
			<strong>النسخة البطيئة</strong>
		</li>
	</ul>
<p>
		يمكننا حساب كلّ ناتج جمع فرعي ممكن.
	</p>

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

	<p>
		فمثلًا إن كان لدينا <code>‎[-1, 2, 3, -9, 11]‎</code>:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_98" style="">
<span class="com">// ‫نبدأ بِ‍ ‎-1:</span><span class="pln">
</span><span class="pun">-</span><span class="lit">1</span><span class="pln">
</span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </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="lit">3</span><span class="pln">
</span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </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="lit">3</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(-</span><span class="lit">9</span><span class="pun">)</span><span class="pln">
</span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </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="lit">3</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(-</span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">11</span><span class="pln">

</span><span class="com">// ‫نبدأ بِ‍ 2:</span><span class="pln">
</span><span class="lit">2</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(-</span><span class="lit">9</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="lit">3</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(-</span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">11</span><span class="pln">

</span><span class="com">// نبدأ بِ‍‏‫ 3:</span><span class="pln">
</span><span class="lit">3</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(-</span><span class="lit">9</span><span class="pun">)</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(-</span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">11</span><span class="pln">

</span><span class="com">// نبدأ بِ‍‏‫ ‎-9:</span><span class="pln">
</span><span class="pun">-</span><span class="lit">9</span><span class="pln">
</span><span class="pun">-</span><span class="lit">9</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">11</span><span class="pln">

</span><span class="com">// نبدأ بِ‍‏‫ 11:</span><span class="pln">
</span><span class="lit">11</span></pre>

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

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_100" style="">
<span class="kwd">function</span><span class="pln"> getMaxSubSum</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let maxSum </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">// إن لم نأخذ أيّ عنصر، فسنُرجع الصفر 0</span><span class="pln">

  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let 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"> arr</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let sumFixedStart </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">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let j </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&lt;</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      sumFixedStart </span><span class="pun">+=</span><span class="pln"> arr</span><span class="pun">[</span><span class="pln">j</span><span class="pun">];</span><span class="pln">
      maxSum </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">maxSum</span><span class="pun">,</span><span class="pln"> sumFixedStart</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"> maxSum</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> getMaxSubSum</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="pun">-</span><span class="lit">9</span><span class="pun">])</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getMaxSubSum</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="pun">-</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</span><span class="pun">])</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 11</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getMaxSubSum</span><span class="pun">([-</span><span class="lit">2</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="pun">);</span><span class="pln"> </span><span class="com">// 3</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getMaxSubSum</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="pun">);</span><span class="pln"> </span><span class="com">// 6</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getMaxSubSum</span><span class="pun">([</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">9</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="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="pun">);</span><span class="pln"> </span><span class="com">// 100</span></pre>

	<p>
		مدى التعقيد الحسابي لهذا الحل هو <a href="https://en.wikipedia.org/wiki/Big_O_notation" rel="external nofollow">O(n<sup>2</sup>)</a>. أي بعبارة أخرى، لو زِدت حجم المصفوفة <em>مرتين اثنتين</em>، فسيزيد وقت عمل الخوارزمية <em>أربع مرات</em> أكثر.
	</p>

	<p>
		يمكن أن تؤدّي هذه الخوازرميات للمصفوفات الكبيرة (نتحدّث عن 1000 و10000 وأكثر) إلى بطء شديد في التنفيذ.
	</p>

	<ul>
<li>
			<strong>النسخة السريعة</strong>
		</li>
	</ul>
<p>
		لنمرّ على عناصر المصفوفة ونحفظ ناتج جمع العناصر الحالي في المتغير <code>s</code>. متى ما صار <code>s</code> سالبًا، نعيّنه صفرًا <code>s=0</code>. إجابتنا على هذا هي أكبر قيمة من هذا المتغير <code>s</code>.
	</p>

	<p>
		لو لم يكن هذا الوصف منطقيًا، فيمكنك مطالعة الشيفرة، قصيرة للغاية:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_73_102" style="">
<span class="kwd">function</span><span class="pln"> getMaxSubSum</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let maxSum </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  let partialSum </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">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let item of arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// لكلّ ‫item في arr</span><span class="pln">
    partialSum </span><span class="pun">+=</span><span class="pln"> item</span><span class="pun">;</span><span class="pln"> </span><span class="com">// نُضيفه إلى ‫partialSum</span><span class="pln">
    maxSum </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">maxSum</span><span class="pun">,</span><span class="pln"> partialSum</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">partialSum </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> partialSum </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">// لو كانت سالبة فالصفر</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> maxSum</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> getMaxSubSum</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="pun">-</span><span class="lit">9</span><span class="pun">])</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getMaxSubSum</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="pun">-</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</span><span class="pun">])</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 11</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getMaxSubSum</span><span class="pun">([-</span><span class="lit">2</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="pun">);</span><span class="pln"> </span><span class="com">// 3</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getMaxSubSum</span><span class="pun">([</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">9</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="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="pun">);</span><span class="pln"> </span><span class="com">// 100</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getMaxSubSum</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="pun">);</span><span class="pln"> </span><span class="com">// 6</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> getMaxSubSum</span><span class="pun">([-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">3</span><span class="pun">])</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0</span></pre>

	<p>
		على الخوارزمية هنا أن تمرّ مرورًا واحدًا فقط على المصفوفة، أي أن التعقيد الحسابي هو O(n)<code>‎</code>.
	</p>

	<p>
		يمكنك أن تجد معلومات مفصّلة أكثر عن الخوارزمية هنا: <a href="http://en.wikipedia.org/wiki/Maximum_subarray_problem" rel="external nofollow">Maximum subarray problem</a>. لو لم يكن هذا واضحًا بعد، فالأفضل لو تتعقّب ما تفعل الخوارزمية في الأمثلة أعلاه، وترى ما تفعله من حسابات. «التعقّب يغني عن ألف كلمة»… ربّما.
	</p>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/array" rel="external nofollow">Arrays</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<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%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-array-methods-r819/" rel="">توابع المصفوفات (Array methods)</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-r817/" rel="">السلاسل النصية (strings)</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">818</guid><pubDate>Thu, 05 Mar 2020 13:09:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x633;&#x644;&#x627;&#x633;&#x644; &#x627;&#x644;&#x646;&#x635;&#x64A;&#x629; (strings) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/34.jpg.e25dbc0c7de5adc20303b2b2ebef4b15.jpg" /></p>
<p>
	تُخَزَّن النصوص في JavaScript كسلاسل نصية أي سلاسل من المحارف (string of charecter). لا يوجد نوع بيانات مستقل للحرف الواحد (char).
</p>

<p>
	الصيغة الداخلية للنصوص هي <a href="https://en.wikipedia.org/wiki/UTF-16" rel="external nofollow">UTF-16</a> دائمًا، ولا تكون مرتبطة بتشفير الصفحة.
</p>

<h2>
	علامات الاقتباس ""
</h2>

<p>
	لنراجع أنواع علامات التنصيص (الاقتباس).
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_6" style=""><span class="pln">let single </span><span class="pun">=</span><span class="pln"> </span><span class="str">'single-quoted'</span><span class="pun">;</span><span class="pln">
let </span><span class="kwd">double</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"double-quoted"</span><span class="pun">;</span><span class="pln">

let backticks </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">backticks</span><span class="pun">`;</span></pre>

<p>
	علامات التنصيص الفردية والثنائية تكون متماثلة. أما الفاصلة العليا المائلة، فَتُتيح لنا تضمين أي تعبير في السلسلة النصية، عبر تضمينها في <code>‎${…}‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_8" style=""><span class="kwd">function</span><span class="pln"> sum</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(`</span><span class="lit">1</span><span class="pln"> </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="pun">{</span><span class="pln">sum</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="com">// 1 + 2 = 3.</span></pre>

<p>
	الميزة الأخرى لاستخدام الفاصلة العلوية المائلة هي إمكانية فصل السلسلة النصية إلى عدة أسطر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_10" style=""><span class="pln">let guestList </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Guests</span><span class="pun">:</span><span class="pln">
 </span><span class="pun">*</span><span class="pln"> </span><span class="typ">John</span><span class="pln">
 </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Pete</span><span class="pln">
 </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Mary</span><span class="pln">
</span><span class="pun">`;</span><span class="pln">

</span><span class="com">// قائمة بالضيوف في أسطر منفصلة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">guestList</span><span class="pun">);</span><span class="pln"> </span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_12" style=""><span class="pln">let guestList </span><span class="pun">=</span><span class="pln"> </span><span class="str">"</span><span class="typ">Guests</span><span class="pun">:</span><span class="pln"> </span><span class="com">// خطأ: رمز غير متوقع</span><span class="pln">
  </span><span class="pun">*</span><span class="pln"> </span><span class="typ">John</span><span class="str">";</span></pre>

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

<p>
	تتيح لنا أيضا الفاصلة العلوية المائلة تحديد "دالة كنموذج" قبل الفاصلة العلوية المائلة الأولى. تكون الصيغة كما يلي: <code>func`string`</code>‎<code>. تُستَدعى الدالة </code>func تلقائيًا، وتستقبل النص والتعابير المُضَمَّنة وتعالجها. يسمى هذا ب "القوالب الملحقة". تجعل هذه الميزة من السهل تضمين قوالب مخصصة، لكنها تستخدم بشكل نادر عمليًا. يمكنك قراءة المزيد عنها في هذا <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates" rel="external nofollow">الدليل</a>.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة تطوير التطبيقات باستخدام لغة JavaScript
		</p>

		<p class="banner-subtitle">
			تعلم البرمجة بلغة جافا سكريبت انطلاقًا من أبسط المفاهيم وحتى بناء تطبيقات حقيقية.
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/javascript-application-development/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<img alt="دورة تطوير التطبيقات باستخدام لغة JavaScript" src="https://academy.hsoub.com/learn/assets/images/courses/javascript-application-development.png">
	</div>
</div>

<h2>
	الرموز الخاصة
</h2>

<p>
	ما زال بالإمكان كتابة نصوص متعددة الأسطر باستخدام علامات الاقتباس الأحادية والثنائية باستخدام ما يسمى ب "رمز السطر الجديد"، والذي يُكتَب <code>‎\n</code>، ويرمز لسطر جديد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_14" style=""><span class="pln">let guestList </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Guests:\n * John\n * Pete\n * Mary"</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">guestList</span><span class="pun">);</span><span class="pln"> </span><span class="com">// قائمة متعددة الأسطر بالضيوف</span></pre>

<p>
	مثلًا، السطرين التاليين متماثلان، لكنهما مكتوبين بطريقة مختلفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_16" style=""><span class="com">// سطران باستخدام رمز السطر الجديد</span><span class="pln">
let str1 </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello\nWorld"</span><span class="pun">;</span><span class="pln"> 

</span><span class="com">// سطران باستخدام سطر جديد عادي والفواصل العليا المائلة </span><span class="pln">
let str2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Hello</span><span class="pln">
</span><span class="typ">World</span><span class="pun">`;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">str1 </span><span class="pun">==</span><span class="pln"> str2</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	يوجد رموز خاصة أخرى أقل انتشارًا.
</p>

<p>
	هذه القائمة كاملة:
</p>

<table>
	<thead>
		<tr>
			<th>
				المحرف
			</th>
			<th>
				الوصف
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<code>‎\n</code>
			</td>
			<td>
				محرف السطر الجديد (Line Feed).
			</td>
		</tr>
		<tr>
			<td>
				<code>‎\r</code>
			</td>
			<td>
				محرف العودة إلى بداية السطر (Carriage Return)، ولا يستخدم بمفرده. تستخدم ملفات ويندوز النصية تركيبة من رمزين ‎<code>\r\n</code> لتمثيل سطر جديد.
			</td>
		</tr>
		<tr>
			<td>
				‎<code>'\</code> , <code>"\</code>
			</td>
			<td>
				علامة اقتباس مزدوجة ومفردة.
			</td>
		</tr>
		<tr>
			<td>
				<code>\\</code>
			</td>
			<td>
				شرطة مائلة خلفية
			</td>
		</tr>
		<tr>
			<td>
				<code>‎\t</code>
			</td>
			<td>
				مسافة جدولة "Tab"
			</td>
		</tr>
		<tr>
			<td>
				‎<code>\b</code>, <code>\f</code>, <code>\v</code>
			</td>
			<td>
				فراغ خلفي (backspace)، محرف الانتقال إلى صفحة جديد (Form Feed)، مسافة جدولة أفقية (Vertical Tab) على التوالي – تُستعمَل للتوافق، ولم تعد مستخدمة.
			</td>
		</tr>
		<tr>
			<td>
				<code>‎\xXX</code>
			</td>
			<td>
				صيغة رمز يونيكود مع عدد ست عشري مُعطى <code>XX</code>، مثال: <code>'‎ \x7A'</code> هي نفسها <code>'z'</code>.
			</td>
		</tr>
		<tr>
			<td>
				<code>‎\uXXXX</code>
			</td>
			<td>
				صيغة رمز يونيكود مع عدد ست عشرية <code>XXXX</code> في تشفير UTF-16، مثلًا، <code>‎\u00A9</code> – هو اليونيكود لرمز حقوق النسخ <code>©</code>. يجب أن يكون مكون من 6 خانات ست عشرية.
			</td>
		</tr>
		<tr>
			<td>
				‎<code>\u{X…XXXXXX}‎</code>
			</td>
			<td>
				(1 إلى 6 أحرف ست عشرية) رمز يونيكود مع تشفير UTF-32 المعطى. تُشَفَّر بعض الرموز الخاصة برمزي يونيكود، فتأخذ 4 بايت. هكذا يمكننا إدخال شيفرات طويلة.
			</td>
		</tr>
	</tbody>
</table>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
}

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<p>
	أمثلة باستخدام حروف يونيكود:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_18" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"\u00A9"</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ©</span><span class="pln">

</span><span class="com">// (رمز نادر من الهيروغليفية الصينية (يونيكود طويل</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"\u{20331}"</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 佫</span><span class="pln">

</span><span class="com">// (رمز وجه مبتسم (يونيكود طويل آخر</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"\u{1F60D}"</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ?</span></pre>

<p>
	لاحظ بدء جميع الرموز الخاصة بشرطة مائلة خلفية <code>\</code>. تدعى أيضا ب "محرف التهريب" (escape character). يمكننا استخدامها أيضًا إن أردنا تضمين علامة اقتباس في النص: مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_20" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'I\'m the Walrus!'</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// I'm the Walrus!</span></pre>

<p>
	يجب إلحاق علامة الاقتباس الداخلية بالشرطة المائلة الخلفية <code>‎\'‎</code>، وإلا فستُعتَبر نهاية السلسلة النصية. لاحظ أن الشرطة المائلة الخلفية <code>\</code> تعمل من أجل تصحيح قراءة السلسلة النصية بواسطة JavaScript. ومن ثم تختفي، لذا فإن النص في الذاكرة لا يحتوي على <code>\</code>. يمكننا رؤية ذلك بوضوح باستخدام <code>alert</code> على المثال السابق.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_22" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`</span><span class="pln">I</span><span class="str">'m the Walrus!` ); // I'</span><span class="pln">m the </span><span class="typ">Walrus</span><span class="pun">!</span></pre>

<p>
	لكن ماذا إن أردنا عرض شرطة مائلة خلفية ضمن النص؟ يمكن ذلك، لكننا نحتاج إلى تكرارها هكذا <code>\\</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_24" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`</span><span class="typ">The</span><span class="pln"> backslash</span><span class="pun">:</span><span class="pln"> \\</span><span class="pun">`</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// The backslash: \</span></pre>

<h2>
	طول النص
</h2>

<p>
	تحمل الخاصية <code>length</code> طول النص:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_26" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`</span><span class="typ">My</span><span class="pln">\n</span><span class="pun">`.</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3</span></pre>

<p>
	لاحظ أن <code>n\</code> هو رمز خاص، لذا يكون طول السلسلة الفعلي هو 3.
</p>

<h3>
	<strong><code>length</code> هي خاصية</strong>
</h3>

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

<h2>
	الوصول إلى محارف سلسلة
</h2>

<p>
	للحصول على حرف في مكان معين من السلسلة النصية <code>pos</code>، استخدم الأقواس المعقوفة <code>[pos]</code> أو استدعِ التابع <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt" rel="external nofollow">str.charAt(pos)</a><code>‎</code>. يبدأ أول حرف في الموضع رقم صفر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_28" style=""><span class="pln">let str </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="com">// الحرف الأول</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</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="com">// H</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">charAt</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="com">// H</span><span class="pln">

</span><span class="com">// الحرف الأخير</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">[</span><span class="pln">str</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// o</span></pre>

<p>
	الأقواس المعقوفة هي طريقة جديدة للحصول على حرف، بينما التابع <code>charAt</code> موجود لأسباب تاريخية. الاختلاف الوحيد بينهما هو إن لم تجد الأقواس المربعة <code>[]</code> الحرف تُرجِع القيمة <code>undefined</code> بينما يُرجِع <code>charAt</code> نصًا فارغًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_30" style=""><span class="pln">let str </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">

alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">[</span><span class="lit">1000</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// '' (سلسلة نصية فارغ)</span></pre>

<p>
	يمكننا أيضا التنقل خلال جميع محارف سلسلة باستخدام <code>for..of</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_32" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let </span><span class="kwd">char</span><span class="pln"> of </span><span class="str">"Hello"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="kwd">char</span><span class="pun">);</span><span class="pln"> </span><span class="com">// H,e,l,l,o</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	النصوص ثابتة
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_34" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hi'</span><span class="pun">;</span><span class="pln">

str</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="str">'h'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// خطأ</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</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="com">// لا تعمل</span></pre>

<p>
	الطريقة المعتادة هي إنشاء نص جديد وإسناده للمتغير <code>str</code> بدلًا من النص السابق. مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_36" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hi'</span><span class="pun">;</span><span class="pln">

str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'h'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">[</span><span class="lit">1</span><span class="pun">];</span><span class="pln"> </span><span class="com">// تستبدل كامل السلسلة النصية</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> str </span><span class="pun">);</span><span class="pln"> </span><span class="com">// hi</span></pre>

<p>
	سنرى المزيد من الأمثلة عن ذلك في الأجزاء التالية.
</p>

<h2>
	تغيير حالة الأحرف الأجنبية
</h2>

<p>
	يقوم التابع <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase" rel="external nofollow"><code>toLowerCase()‎</code></a> والتابع <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase" rel="external nofollow"><code>toUpperCase()‎</code></a> بِتغيير حالة الأحرف الأجنبية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_38" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'Interface'</span><span class="pun">.</span><span class="pln">toUpperCase</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// INTERFACE</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'Interface'</span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// interface</span></pre>

<p>
	أو إن أردنا بتغيير حالة حرف واحد فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_40" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'Interface'</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">toLowerCase</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 'i'</span></pre>

<h2>
	البحث عن جزء من النص
</h2>

<p>
	يوجد العديد من الطرق للبحث عن جزء من النص ضمن السلسلة النصية.
</p>

<h3>
	str.indexOf
</h3>

<p>
	التابع الأول هو <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf" rel="external nofollow"><code>str.indexOf(substr, pos)‎</code></a>.
</p>

<p>
	يبحث التابع عن <code>substr</code> في <code>str</code> بدءًا من الموضع المحدد <code>pos</code>، ثم يُرجِع الموضع الذي تطابق مع النص أو يُرجِع <code>‎ -1</code> إن لم تعثر على تطابق. مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_42" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Widget with id'</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">'Widget'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">'widget'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// -1</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"id"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span></pre>

<p>
	لم تعثر على شيء في حالة البحث الثانية، إذ البحث هنا حساس لحالة الأحرف.
</p>

<p>
	يتيح لنا المُعامِل الثاني الاختياري البحث من الموضع المُعطَى. مثلًا في الحالة الثالثة، أول ظهور ل <code>"id"</code> هو في الموضع <code>1</code>. لِلبحث عن الظهور التالي له نبدأ البحث من الموضع <code>2</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_44" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Widget with id'</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">'id'</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="com">// 12</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_46" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">'As sly as a fox, as strong as an ox'</span><span class="pun">;</span><span class="pln">

let target </span><span class="pun">=</span><span class="pln"> </span><span class="str">'as'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// لنبحث عنها</span><span class="pln">

let pos </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let foundPos </span><span class="pun">=</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="pln">target</span><span class="pun">,</span><span class="pln"> pos</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">foundPos </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="kwd">break</span><span class="pun">;</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Found</span><span class="pln"> at $</span><span class="pun">{</span><span class="pln">foundPos</span><span class="pun">}`</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
  pos </span><span class="pun">=</span><span class="pln"> foundPos </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> </span><span class="com">// استمر بالبحث من الموضع التالي</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن تقصير الخوارزمية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_48" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"As sly as a fox, as strong as an ox"</span><span class="pun">;</span><span class="pln">
let target </span><span class="pun">=</span><span class="pln"> </span><span class="str">"as"</span><span class="pun">;</span><span class="pln">

let pos </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="kwd">while</span><span class="pln"> </span><span class="pun">((</span><span class="pln">pos </span><span class="pun">=</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="pln">target</span><span class="pun">,</span><span class="pln"> pos </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">))</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> pos </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<h4>
	<strong><code>str.lastIndexOf(substr, position)‎</code></strong>
</h4>

<p>
	يوجد أيضًا تابع مشابه <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf" rel="external nofollow"><code>str.lastIndexOf(substr, position)‎</code></a> والذي يبدأ البحث من نهاية السلسلة النصية حتى بدايتها. أي أنه يعيد موضع ظهور النص المبحوث عنه انطلاقًا من نهاية السلسلة.
</p>

<p>
	يوجد خلل طفيف عند استخدام <code>indexOf</code> في <code>if</code>. فلا يمكن وضعها بداخل <code>if</code> بالطريقة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_50" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Widget with id"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">str</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"Widget"</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">"We found it"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// لا تعمل!</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا يتحقق الشرط في المثال السابق لأن <code>str.indexOf("Widget")‎</code> يُرجِع <code>0</code> (ما يعني وجود تطابق في الموضع الأول) رغم عثور التابع على الكلمة، لكن <code>if</code> تعد القيمة <code>0</code> على أنها <code>false</code>. لذا يجب أن نفحص عدم وجود القيمة <code>-‎ 1</code> هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_52" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Widget with id"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">str</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"Widget"</span><span class="pun">)</span><span class="pln"> </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">
    alert</span><span class="pun">(</span><span class="str">"We found it"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// تعمل الآن</span><span class="pln">
</span><span class="pun">}</span></pre>

<h4>
	خدعة NOT على مستوى البِت
</h4>

<p>
	إحدى الخدع القديمة هي العامل الثنائي NOT <code>~</code> الذي تعمل على مستوى البِت. فهو يُحَوِّل العدد إلى عدد صحيح بصيغة 32-بِت (يحذف الجزء العشري إن وجد) ثم يُحوِّل جميع البتات إلى تمثيلها الثنائي. عمليًا، يعني ذلك شيئًا بسيطًا: بالنسبة للأعداد الصحيحة بصيغة 32-بِت <code>‎~n</code> تساوي <code>‎-(n+1)‎</code>. مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_54" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">~</span><span class="lit">2</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// -3 == -(2+1)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">~</span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// -2 == -(1+1)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">~</span><span class="lit">0</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// -1 == -(0+1)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">~-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0 == -(-1+1)</span></pre>

<p>
	كما نرى، يكون <code>‎~‎n</code> صفرًا فقط عندما تكون <code>n == -1</code> (وذلك لأي عدد صحيح <code>n</code> ذي إشارة). لذا، يكون ناتج الفحص <code>if ( ~str.indexOf("...") )‎</code> صحيحًا إذا كانت نتيجة <code>indexOf</code> لا تساوي <code>‎-1</code>. بمعنى آخر تكون القيمة <code>true</code> إذا وُجِد تطابق.
</p>

<p>
	الآن، يمكن استخدام هذه الحيلة لتقصير الفحص باستخدام <code>indexOf</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_56" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Widget"</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">str</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"Widget"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'Found it!'</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>

<p>
	تذكر أن الشرط <code>if (~str.indexOf(...))‎</code> يعمل بالصيغة «إن وُجِد».
</p>

<p>
	حتى نكون دقيقين، عندما تُحَوَّل الأرقام إلى صيغة 32-بِت باستخدام المعامل <code>~</code> يوجد أعداد أخرى تُعطي القيمة <code>0</code>، أصغر هذه الأعداد هي <code>‎~4294967295 == 0</code>. ما يجعل هذا الفحص صحيحًا في حال النصوص القصيرة فقط.
</p>

<p>
	لا نجد هذه الخدعة حاليًا سوى في الشيفرات القديمة، وذلك لأن JavaScript وفرت التابع <code>‎.includes</code> (ستجدها في الأسفل).
</p>

<h3>
	includes, startsWith, endsWith
</h3>

<p>
	يُرجِع التابع الأحدث <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes" rel="external nofollow"><code>str.includes(substr, pos)‎</code></a> القيمة المنطقية <code>true</code> أو <code>false</code> وفقًا لما إن كانت السلسلة النصية <code>str</code> تحتوي على السلسلة النصية الفرعية <code>substr</code>. هذه هي الطريقة الصحيحة في حال أردنا التأكد من وجود تطابق جزء من سلسلة ضمن سلسلة أخرى، ولا يهمنا موضعه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_58" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Widget with id"</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="str">"Widget"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="str">"Bye"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// false</span></pre>

<p>
	المُعامِل الثاني الاختياري للتابع <code>str.includes</code> هو الموضع المراد بدء البحث منه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_60" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Widget"</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="str">"id"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Widget"</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="str">"id"</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="com">// false</span></pre>

<p>
	يعمل التابعان <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith" rel="external nofollow"><code>str.startsWith</code></a> و <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith" rel="external nofollow"><code>str.endsWith</code></a> بما هو واضح من مسمياتهما، "سلسلة نصية تبدأ بـ"، و "سلسلة نصية تنتهي بـ" على التوالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_62" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Widget"</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="str">"Wid"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true, </span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Widget"</span><span class="pun">.</span><span class="pln">endsWith</span><span class="pun">(</span><span class="str">"get"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true, </span></pre>

<h2>
	جلب جزء من نص
</h2>

<p>
	يوجد 3 توابع في JavaScript لجلب جزء من سلسلة نصية هي: <code>substring</code>، و<code>substr</code>، و<code>slice</code>.
</p>

<h3>
	<strong><code>str.slice(start [, end])‎</code></strong>
</h3>

<p>
	يُرجِع جزءًا من النص بدءًا من الموضع <code>start</code> وحتى الموضع <code>end</code> (بما لا يتضمن <code>end</code>). مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_64" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"stringify"</span><span class="pun">;</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 'strin'</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">slice</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="pun">);</span><span class="pln"> </span><span class="com">// 's'</span></pre>

<p>
	إن لم يكن هناك مُعامل ثانٍ، فسيقتطع التابع<code>slice</code> الجزء المحدد من الموضع <code>start</code> وحتى نهاية النص:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_66" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"stringify"</span><span class="pun">;</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</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="pun">);</span><span class="pln"> </span><span class="com">// ringify</span></pre>

<p>
	يمكن أيضًا استخدام عدد سالبًا مع <code>start</code> أو <code>end</code>، وذلك يعني أن الموضع يُحسَب بدءًا من نهاية السلسلة النصية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_68" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"stringify"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// تبدأ من الموضع الرابع من اليمين، إلى الموضع الأول من اليمين</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">(-</span><span class="lit">4</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"> </span><span class="com">// gif</span></pre>

<h3>
	<strong><code>str.substring(start [, end])‎</code></strong>
</h3>

<p>
	يُرجِع هذا التابع جزءًا من النص الواقع بين الموضع <code>start</code> والموضع <code>end</code>. يشبه هذا التابع تقريبًا التابع <code>slice</code>، لكنه يسمح بكون المعامل <code>start</code> أكبر من <code>end</code>. مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_70" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"stringify"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// substring الأمرين التاليين متماثلين بالنسبة لـ </span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">substring</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "ring"</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">substring</span><span class="pun">(</span><span class="lit">6</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="com">// "ring"</span><span class="pln">

</span><span class="com">// slice لكن ليس مع</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</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="lit">6</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "ring" (نفس النتيجة السابقة)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">(</span><span class="lit">6</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="com">// "" (نص فارغ)</span></pre>

<p>
	بعكس <code>slice</code>، القيم السالبة غير مدعومة ضمن المعاملات، وتقيَّم إلى <code>0</code> إن مُرِّرت إليه.
</p>

<h3>
	<strong><code>str.substr(start [, length])‎</code></strong>
</h3>

<p>
	يُرجِع هذا التابع الجزء المطلوب من النص، بدءًا من <code>start</code> وبالطول <code>length</code> المُعطى. بعكس التوابع السابقة، يتيح لنا هذا التابع تحديد طول النص المطلوب بدلًا من موضع نهايته:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_72" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"stringify"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// خذ 4 أحرف من الموضع 2</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">substr</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ring</span></pre>

<p>
	يمكن أن يكون المُعامِل الأول سالبًا لتحديد الموضع بدءًا من النهاية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_74" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"stringify"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// حرفين ابتداءًا من الموضع الرابع</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">substr</span><span class="pun">(-</span><span class="lit">4</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="com">// gi</span></pre>

<p>
	 
</p>

<table>
	<thead>
		<tr>
			<th>
				التابع
			</th>
			<th>
				يقتطع ...
			</th>
			<th>
				المواضع السالبة
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<code>slice(start, end)‎</code>
			</td>
			<td>
				من الموضع <code>start</code> إلى الموضع <code>end</code> (بما لا يتضمن <code>end</code>)
			</td>
			<td>
				مسموحة لكلا المعاملين
			</td>
		</tr>
		<tr>
			<td>
				<code>substring(start, end)‎</code>
			</td>
			<td>
				ما بين الموضع <code>start</code> والموضع <code>end</code>
			</td>
			<td>
				غير مسموحة وتصبح <code>0</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>substr(start, length)‎</code>
			</td>
			<td>
				أرجع الأحرف بطول <code>length</code> بدءًا من <code>start</code>
			</td>
			<td>
				مسموحة للمعامل <code>start</code>
			</td>
		</tr>
	</tbody>
</table>

<p>
	<strong>أيها تختار؟</strong>
</p>

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

<p>
	ما بين الخيارين الآخرين، <code>slice</code> هو أكثر مرونة، فهو يسمح بتمرير مُعامِلات سالبة كما أنه أقصر في الكتابة. لذا، من الكافِ تذكر <code>slice</code> فقط من هذه التوابع الثلاث.
</p>

<h2>
	موازنة النصوص
</h2>

<p>
	توازن السلاسل النصية حرفًا حرفًا بترتيب أبجدي كما عرفنا في فصل <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%B9%D8%A7%D9%85%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%88%D8%A7%D8%B2%D9%86%D8%A9-r700/" rel="">معاملات الموازنة</a>.
</p>

<p>
	بالرغم من ذلك، يوجد بعض الحالات الشاذة.
</p>

<p>
	1- الحرف الأجنبي الصغير دائما أكبر من الحرف الكبير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_78" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'a'</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="str">'Z'</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	2- الأحرف المُشَكَلَة خارج النطاق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_80" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'Österreich'</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="str">'Zealand'</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'سوريا'</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="str">'تُونس'</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// false</span></pre>

<p>
	قد يقود ذلك إلى نتائج غريبة إن رتبنا مثلًا بين أسماء بلدان، فيتوقع الناس دائمًا أن <code>Zealand</code> تأتي بعد <code>Österreich</code> في القائمة وأن تونس تأتي قبل سوريا وهكذا. لفهم ما يحدث، لنراجع تمثيل النصوص الداخلي في JavaScript.
</p>

<p>
	جميع النصوص مشفرة باستخدام <a href="https://en.wikipedia.org/wiki/UTF-16" rel="external nofollow">UTF-16</a>. يعني أن: لكل حرف رمز عددي مقابل له. يوجد دوال خاصة تسمح بالحصول على الحرف من رمزه والعكس.
</p>

<h3>
	<strong><code>str.codePointAt(pos)‎</code></strong>
</h3>

<p>
	يُرجِع هذا التابع الرمز العددي الخاص بالحرف المعطى في الموضع <code>pos</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_76" style=""><span class="com">// لدى الأحرف المختلفة في الحالة رموز مختلفة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"z"</span><span class="pun">.</span><span class="pln">codePointAt</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="com">// 122</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Z"</span><span class="pun">.</span><span class="pln">codePointAt</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="com">// 90</span></pre>

<h3>
	<strong><code>String.fromCodePoint(code)‎</code></strong>
</h3>

<p>
	يُنشِئ حرفًا من رمزه العددي <code>code</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_82" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">String</span><span class="pun">.</span><span class="pln">fromCodePoint</span><span class="pun">(</span><span class="lit">90</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Z</span></pre>

<p>
	يمكننا إضافة حرف يونيكود باستخدام رمزه بواسطة <code>‎\u</code> متبوعة بالرمز الست عشري:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_84" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'\u005a'</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Z</span></pre>

<p>
	يُمثَّل العدد العشري 90 بالعدد 5a في النظام الست عشري.
</p>

<p>
	لنرَ الآن الأحرف ذات الرموز <code>65..220</code> (الأحرف اللاتينية وأشياء إضافية) عبر إنشاء نصوص منها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_86" style=""><span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">65</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">220</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">
  str </span><span class="pun">+=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">.</span><span class="pln">fromCodePoint</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">
alert</span><span class="pun">(</span><span class="pln"> str </span><span class="pun">);</span><span class="pln">
</span><span class="com">// ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~������</span><span class="pln">
</span><span class="com">// ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁ ÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ</span></pre>

<p>
	تبدأ الأحرف الكبيرة كما ترى، ثم أحرف خاصة، ثم الأحرف الصغيرة، ثم <code>Ö</code> بالقرب من نهاية المخرجات.
</p>

<p>
	يصبح الآن واضحًا لم <code>a &gt; Z</code>. أي توازن الأحرف بواسطة قيمها العددية. فالرمز العددي الأكبر يعني أن الحرف أكبر. الرمز للحرف <code>a</code> هو 97‎ وهو أكبر من الرمز العددي للحرف <code>Z</code> الذي هو 90.
</p>

<ul>
	<li>
		تأتي الأحرف الصغيرة بعد الأحرف الكبيرة دائمًا لأن رموزها العددية دائمًا أكبر.
	</li>
	<li>
		تكون بعض الأحرف مثل <code>Ö</code> بعيدة عن الأحرف الهجائية. هنا، قيمة الحرف هذا أكبر من أي حرف بين <code>a</code> و <code>z</code>.
	</li>
</ul>

<h3>
	موازنات صحيحة
</h3>

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

<p>
	لحسن الحظ، تدعم جميع المتصفحات الحديثة المعيار العالمي <a href="http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf" rel="external nofollow">ECMA 402</a>(IE10- الذي يتطلب المكتبة الاضافية <a href="https://github.com/andyearnshaw/Intl.js/" rel="external nofollow">Intl.JS</a>)، إذ يوفر تابعًا خاصًا لموازنة النصوص بلغات متعددة، وفقًا لقواعدها.
</p>

<p>
	يُرجِع استدعاء التابع <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare" rel="external nofollow"><code>str.localeCompare(str2)‎</code></a> عددًا يحدد ما إن كان النص <code>str</code> أصغر، أو يساوي، أو أكبر من النص <code>str2</code> وفقًا لقواعد اللغة المحلية:
</p>

<ul>
	<li>
		يُرجِع قيمة سالبة إن كان <code>str</code> أصغر من <code>str2</code>.
	</li>
	<li>
		يُرجِع قيمة موجبة إن كان <code>str</code> أكبر من <code>str2</code>.
	</li>
	<li>
		يُرجِع <code>0</code> إن كانا متساويين.
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_88" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'Österreich'</span><span class="pun">.</span><span class="pln">localeCompare</span><span class="pun">(</span><span class="str">'Zealand'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// -1</span></pre>

<p>
	في الحقيقة، لهذه الدالة مُعامِلين إضافيين كما في <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare" rel="external nofollow">توثيقها على MDN</a>، إذ يسمح هذان المُعاملان بتحديد اللغة (تؤخذ من بيئة العمل تلقائيًا، ويعتمد ترتيب الأحرف على اللغة) بالإضافة إلى إعداد قواعد أخرى مثل الحساسية تجاه حالة الأحرف، أو ما إن كان يجب معاملة <code>"a"</code> و <code>"á"</code> بالطريقة نفسها …الخ.
</p>

<h2>
	ما خلف الستار، يونيكود
</h2>

<p>
	<strong>معلومات متقدمة</strong>
</p>

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

<h3>
	أزواج بديلة (Surrogate pairs)
</h3>

<p>
	لكل الأحرف المستخدمة بكثرة رموز عددية (code) مؤلفة من 2-بايت. لدى أحرف اللغات الأوروبية، والأرقام، وحتى معظم الرموز الهيروغليفية تمثيل من 2-بايت.
</p>

<p>
	لكن، نحصل من 2-بايت 65536 على تركيبًا فقط وذلك غير كافٍ لكل الرموز (symbol) المُحتَمَلَة، لذا فإن الرموز (symbol) النادرة مرمزة بزوج من المحارف بحجم 2-بايت يسمى "أزواج بديلة" (Surrogate pairs).
</p>

<p>
	طول كل رمز هو <code>2</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_90" style=""><span class="com">// في الرياضيات X الحرف </span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'?'</span><span class="pun">.</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span><span class="pln">

</span><span class="com">// وجه ضاحك بدموع</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'?'</span><span class="pun">.</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span><span class="pln">

</span><span class="com">// حرف صيني هيروغليفي نادر</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'?'</span><span class="pun">.</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span></pre>

<p>
	لاحظ أن الأزواج البديلة لم تكن موجودة منذ إنشاء JavaScript، ولذا لا تعالج بشكل صحيح بواسطة اللغة. في النصوص السابقة لدينا رمز واحد فقط، لكن طول النص <code>length</code> ظهر على أنه <code>2</code>.
</p>

<p>
	التابعان <code>String.fromCodePoint</code> و <code>str.codePointAt</code> نادران وقليلا الاستخدام، إذ يتعاملان مع الأزواج البديلة بصحة. وقد ظهرت مؤخرًا في اللغة. في السابق كان هنالك التابعان <code>String.fromCharCode</code> و <code>str.charCodeAt</code> فقط. هذان التابعان يشبهان <code>fromCodePoint</code> و <code>codePointAt</code>، لكنهما لا يتعاملان مع الأزواج البديلة.
</p>

<p>
	قد يكون الحصول على رمز (symbol) واحد صعبًا، لأن الأزواج البديلة تُعامَل معاملة حرفين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_92" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'?'</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="com">// رموز غريبة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'?'</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"> </span><span class="com">// أجزاء من الزوج البديل</span></pre>

<p>
	لاحظ أن أجزاء الزوج البديل لا تحمل أي معنى إذا كانت منفصلة عن بعضها البعض. لذا فإن ما يعرضه مر <code>alert</code> في الأعلى هو شيء غير مفيد.
</p>

<p>
	يمكن تَوَقُّع الأزواج البديلة عمليًا بواسطة رموزها: إن كان الرمز العددي لحرف يقع في المدى <code>0xd800..0xdbff</code>، فإنه الجزء الأول من الزوج البديل. أما الجزء الثاني فيجب أن يكون في المدى <code>0xdc00..0xdfff</code>. هذا المدى محجوز للأزواج البديلة وفقًا للمعايير المتبعة.
</p>

<p>
	وفقًا للحالة السابقة، سنستعمل التابع <code>charCodeAt</code> الذي لا يتعامل مع الأزواج البديلة، لذا فإنه يُرجِع أجزاء الرمز:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_94" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'?'</span><span class="pun">.</span><span class="pln">charCodeAt</span><span class="pun">(</span><span class="lit">0</span><span class="pun">).</span><span class="pln">toString</span><span class="pun">(</span><span class="lit">16</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// d835، ما بين  0xd800 و 0xdbff</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'?'</span><span class="pun">.</span><span class="pln">charCodeAt</span><span class="pun">(</span><span class="lit">1</span><span class="pun">).</span><span class="pln">toString</span><span class="pun">(</span><span class="lit">16</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// dcb3، ما بين 0xdc00  و 0xdfff</span></pre>

<p>
	نجد أن العدد الست عشري الأول d835 يقع بين 0xd800 و 0xdbff، والعدد الست عشري الثاني يقع بين 0xdc00 و 0xdfff وهذا يؤكد أنها من الأزواج البديلة.
</p>

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

<h3>
	علامات التشكيل وتوحيد الترميز
</h3>

<p>
	يوجد حروف مركبة في الكثير من اللغات والتي تتكون من الحرف الرئيسي مع علامة فوقه/تحته. مثلًا، يمكن للحرف <code>a</code> أن يكون أساسًا للأحرف التالية: <code>àáâäãåā</code>. لدى معظم الحروف المركبة رمزها الخاص بها في جدول UTF-16. لكن ليس جميعها، وذلك لوجود الكثير من الاحتمالات.
</p>

<p>
	لدعم التراكيب الأساسية، تتيح لنا UTF-16 استخدام العديد من حروف يونيكود: الحرف الرئيسي متبوعًا بعلامة أو أكثر لتشكيله. مثلًا، إن كان لدينا <code>S</code> متبوعًا بالرمز الخاص "النقطة العلوية" (التي رمزها <code>‎ \u0307</code>). فسيُعرَض ك Ṡ.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_96" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'S\u0307'</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Ṡ</span></pre>

<p>
	إن احتجنا إلى رمز آخر فوق أو تحت الحرف فلا مشكلة، أضِف العلامة المطلوبة فقط. مثلًا، إن ألحقنا حرف "نقطة بالأسفل" (رمزها <code>‎ \u0323</code>)، فسنحصل على "S بنقاط فوقه وتحته"، <code>Ṩ</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_98" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'S\u0307\u0323'</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Ṩ</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_100" style=""><span class="com">// S + نقطة في الأعلى + نقطة في الأسفل</span><span class="pln">
let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'S\u0307\u0323'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// Ṩ</span><span class="pln">

</span><span class="com">// S + نقطة في الأسفل + نقطة في الأعلى</span><span class="pln">
let s2 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'S\u0323\u0307'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// Ṩ, </span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`</span><span class="pln">s1</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">s1</span><span class="pun">},</span><span class="pln"> s2</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">s2</span><span class="pun">}`</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> s1 </span><span class="pun">==</span><span class="pln"> s2 </span><span class="pun">);</span><span class="pln"> </span><span class="com">// خطأ بالرغم من أن الحرفين متساويان ظاهريًا</span></pre>

<p>
	لحل ذلك، يوجد خوارزمية تدعى "توحيد ترميز اليونيكود" (unicode normalization) والتي تُعيد كل نص إلى الصيغة الطبيعية المستقلة له.
</p>

<p>
	هذه الخوارزمية مُضَمَّنة في التابع <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize" rel="external nofollow"><code>str.normalize()‎</code></a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_102" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"S\u0307\u0323"</span><span class="pun">.</span><span class="pln">normalize</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">"S\u0323\u0307"</span><span class="pun">.</span><span class="pln">normalize</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	من المضحك في حالتنا أن <code>normalize()‎</code> تجمع سلسلة من 3 أحرف مع بعضها بعضًا إلى حرف واحد: <code>‎ \u1e68</code> (الحرف S مع النقطتين).
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_104" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"S\u0307\u0323"</span><span class="pun">.</span><span class="pln">normalize</span><span class="pun">().</span><span class="pln">length </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"S\u0307\u0323"</span><span class="pun">.</span><span class="pln">normalize</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">"\u1e68"</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

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

<p>
	إن أردت تعلم المزيد عن قواعد التوحيد واختلافاتها - فستجدها في ملحق معايير اليونيكود: <a href="http://www.unicode.org/reports/tr15/" rel="external nofollow">نماذج توحيد ترميز اليونيكود</a>، لكن للأغراض العملية المتعارفة فالمعلومات السابقة تفي بالغرض.
</p>

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

<ul>
	<li>
		يوجد 3 أنواع لِعلامات الاقتباس. تسمح الشرطات العلوية المائلة للنص بالتوسع لأكثر من سطر وتضمين التعبير <code>‎${…}‎</code>.
	</li>
	<li>
		النصوص في JavaScript مُشَفَّرة بواسطة UTF-16.
	</li>
	<li>
		يمكننا استخدام أحرف خاصة مثل <code>‎ \n</code> وإدخال أحرف باستخدام رمز يونيكود الخاص بها باستخدام <code>‎\u...‎</code>.
	</li>
	<li>
		استخدم <code>[]</code> للحصول على حرف ضمن سلسلة نصية.
	</li>
	<li>
		للحصول على جزء من النص، استخدم: <code>slice</code> أو <code>substring</code>.
	</li>
	<li>
		للتحويل من أحرف كبيرة/صغيرة، استخدم: <code>toLowerCase</code> أو <code>toUpperCase</code>.
	</li>
	<li>
		للبحث عن جزء من النص، استخدم: <code>indexOf</code>، أو <code>includes</code> أو <code>startsWith</code> أو <code>endsWith</code> للفحص البسيط.
	</li>
	<li>
		لموازنة النصوص وفقًا للغة، استخدم: <code>localeCompare</code>، وإلا فستوازن برموز الحروف.
	</li>
</ul>

<p>
	يوجد الكثير من التوابع الأخرى المفيدة في النصوص:
</p>

<ul>
	<li>
		<code>str.trim()‎</code> تحذف ("تقتطع") المسافات الفارغة من بداية ونهاية النص.
	</li>
	<li>
		<code>str.repeat(n)‎</code> تُكرِّر النص <code>n</code> مرة.
	</li>
	<li>
		والمزيد، يمكن الاطلاع عليها في <a href="https://wiki.hsoub.com/JavaScript/String" rel="external">موسوعة حسوب</a>.
	</li>
</ul>

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

<h2>
	تمارين
</h2>

<h3>
	حول الحرف الأول إلى حرف كبير
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	اكتب دالة باسم <code>ucFirst(str)‎</code> تُرجِع النص <code>str</code> مع تكبير أول حرف فيه، مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_106" style=""><span class="pln">ucFirst</span><span class="pun">(</span><span class="str">"john"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">;</span></pre>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<p>
		لا يمكننا استبدال الحرف الأول، لأن النصوص في JavaScript غير قابلة للتعديل. لكن، يمكننا إنشاء نص جديد وفقًا للنص الموجود، مع تكبير الحرف الأول:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_110" style=""><span class="pln">let newStr </span><span class="pun">=</span><span class="pln"> str</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">toUpperCase</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span></pre>

	<p>
		لكن، يوجد مشكلة صغيرة، وهي إن كان <code>str</code> فارغًا، فسيصبح <code>str[0]‎</code> قيمة غير معرفة <code>undefined</code>، ولأن <code>undefined</code> لا يملك الدالة <code>toUpperCase()‎</code> فسيظهر خطأ.
	</p>

	<p>
		يوجد طريقتين بديلتين هنا: 1- استخدام <code>str.charAt(0)‎</code>، لأنها تُرجِع نصًا دائمًا (ربما نصًا فارغًا). 2- إضافة اختبار في حال كان النص فارغًا.
	</p>

	<p>
		هنا الخيار الثاني:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_112" style=""><span class="kwd">function</span><span class="pln"> ucFirst</span><span class="pun">(</span><span class="pln">str</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">str</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> str</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> str</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">toUpperCase</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</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="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> ucFirst</span><span class="pun">(</span><span class="str">"john"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// John</span></pre>
</div>

<h3>
	فحص وجود شيء مزعج
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	اكتب دالة باسم <code>checkSpam(str)‎</code> تُرجِع <code>true</code> إن كان <code>str</code> يحوي 'viagra' أو 'XXX'، وإلا فتُرجِع <code>false</code>. يجب أن لا تكون الدالة حساسة لحالة الأحرف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_114" style=""><span class="pln">checkSpam</span><span class="pun">(</span><span class="str">'buy ViAgRA now'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
checkSpam</span><span class="pun">(</span><span class="str">'free xxxxx'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
checkSpam</span><span class="pun">(</span><span class="str">"innocent rabbit"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">false</span></pre>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<p>
		لجعل البحث غير حساس لحالة الأحرف، نحوِّل النص إلى أحرف صغيرة ومن ثم نبحث فيه على النص المطلوب:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_116" style=""><span class="kwd">function</span><span class="pln"> checkSpam</span><span class="pun">(</span><span class="pln">str</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let lowerStr </span><span class="pun">=</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">();</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> lowerStr</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="str">'viagra'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> lowerStr</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="str">'xxx'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> checkSpam</span><span class="pun">(</span><span class="str">'buy ViAgRA now'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> checkSpam</span><span class="pun">(</span><span class="str">'free xxxxx'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> checkSpam</span><span class="pun">(</span><span class="str">"innocent rabbit"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span></pre>
</div>

<h3>
	قص النص
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	انشئ دالة باسم <code>truncate(str, maxlength)‎</code> تفحص طول النص <code>str</code> وتستبدل نهايته التي تتجاوز الحد <code>maxlength</code> بالرمز <code>"…"</code> لجعل طولها يساوي <code>maxlength</code> بالضبط. يجب أن تكون مخرجات الدالة النص المقصوص (في حال حدث ذلك). مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_118" style=""><span class="pln">truncate</span><span class="pun">(</span><span class="str">"What I'd like to tell on this topic is:"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"What I'd like to te…"</span><span class="pln">

truncate</span><span class="pun">(</span><span class="str">"Hi everyone!"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hi everyone!"</span></pre>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<p>
		الطول الكلي هو <code>maxlength</code>، لذا فإننا نحتاج لقص النص إلى أقصر من ذلك بقليل لإعطاء مساحة للنقط <code>"…"</code>. لاحظ أن هناك حرف يونيكود واحد للحرف <code>"…"</code>. وليست ثلاث نقاط.
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_122" style=""><span class="kwd">function</span><span class="pln"> truncate</span><span class="pun">(</span><span class="pln">str</span><span class="pun">,</span><span class="pln"> maxlength</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">str</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&gt;</span><span class="pln"> maxlength</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln">
    str</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> maxlength </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="str">'…'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> str</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>
</div>

<h3>
	استخراج المال
</h3>

<p class="task__importance">
	الأهمية: 4
</p>

<p>
	لدينا قيمة بالشكل <code>"‎ $120"</code>، إذ علامة الدولار تأتي أولًا ومن ثم العدد. أنشِئ دالة باسم <code>extractCurrencyValue(str)‎</code> تستخرج القيمة العددية من نصوص مشابهة وإرجاعها. مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_124" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> extractCurrencyValue</span><span class="pun">(</span><span class="str">'$120'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> </span><span class="lit">120</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8735_126" style=""><span class="kwd">function</span><span class="pln"> extractCurrencyValue</span><span class="pun">(</span><span class="pln">str</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">str</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="pun">}</span></pre>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/string" rel="external nofollow">Strings</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript Language</a>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-arrays-r818/" rel="">المصفوفات (arrays)</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A3%D8%B9%D8%AF%D8%A7%D8%AF-r816/" rel="">الأعداد</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">817</guid><pubDate>Mon, 02 Mar 2020 13:06:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x623;&#x639;&#x62F;&#x627;&#x62F; (numbers) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A3%D8%B9%D8%AF%D8%A7%D8%AF-numbers-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r816/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/33.jpg.96ba69a8a2ac1e25d6ce623adf2a9604.jpg" /></p>
<p>
	يوجد نوعان من الأعداد في JavaScript:
</p>

<ol>
	<li>
		أعداد عادية تخزَّن بصيغة 64-بت <a href="https://en.wikipedia.org/wiki/IEEE_754-2008_revision" rel="external nofollow">IEEE-754</a>، تُعرف أيضًا ب "الأعداد العشرية مضاعفة الدقة" (double precision floating point numbers). هذا النوع هو ما سنستعلمه أغلب الوقت وسنسلط عليه الضوء في هذا الفصل.
	</li>
	<li>
		أعداد صحيحة كبيرة (BigInt numbers) تمثِّل عددًا صحيحًا متغير الحجم، إذ قد نلجأ إليها أحيانًا لأن النوع السابق لا يمكن أن يتجاوز القيمة 2^53 أو أن تقل عن -2^53، وسنخصص لهذا النوع فصلًا خاصًا به نظرًا للحاجة إليه في حالات خاصة.
	</li>
</ol>

<p>
	حاليًا، لِنتوسع عن ما نعرفه عنها، وننتقل إلى الحديث عن النوع الأول، الأعداد العادية.
</p>

<h2>
	طرائق أخرى لكتابة عدد
</h2>

<p>
	تخيل أننا نريد كتابة 1 بليون. الطريقة الواضحة هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_7" style=""><span class="pln">let billion </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1000000000</span><span class="pun">;</span></pre>

<p>
	لكن، نتجنب غالبًا كتابة سلسلة طويلة من الأصفار في الحياة الواقعية لأنه من السهل الخطأ في ذلك ولكون ذلك الأمر يأخذ وقتًا أكثر. نكتب غالبًا شيئا مثل <code>"1bn"</code> بدلًا من بليون أو <code>"7.3bn"</code> بدلًا من 7 بليون و 300 مليون. يمكن تطبيق الأمر ذاته مع الأعداد الكبيرة.
</p>

<p>
	نُقَصِّر أرقام الأعداد في JavaScript بإضافة الحرف <code>"e"</code> للعدد وتحديد عدد الأصفار فيه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_11" style=""><span class="com">// بليون، حرفيًا: 1 وجانبه 9 أصفار</span><span class="pln">
let billion </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1e9</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">7.3e9</span><span class="pln"> </span><span class="pun">);</span><span class="pln">  </span><span class="com">// 7,300,000,000</span></pre>

<p>
	بمعنى آخر، يضرب الشكل <code>"XeY"</code> العدد X في <code>1</code> متبوعًا بعدد Y من الأصفار.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_13" style=""><span class="lit">1e3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">1000</span><span class="pln">
</span><span class="lit">1.23e6</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1.23</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">1000000</span></pre>

<p>
	لنكتب الآن شيئَا صغيرًا جدًا. مثلًا، جزء من المليون من الثانية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_15" style=""><span class="pln">let ms </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.000001</span><span class="pun">;</span></pre>

<p>
	كما قمنا سابقًا، يمكن استخدام <code>"e"</code> لتجنب كتابة الأصفار، يمكننا القول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_17" style=""><span class="pln">let ms </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1e-6</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ستة أصفار على يسار 1</span></pre>

<p>
	إن قمنا بعد الأصفار في <code>0.000001</code>، سنجد عددها 6. لذا يكون الرقم <code>1e-6</code>.
</p>

<p>
	بمعنى آخر، وجود رقم سالب بعد <code>"e"</code> يعني القسمة على 1 متبوعًا بِعدد الأصفار المعطى:
</p>

<pre class="ipsCode" id="ips_uid_687_19">// بالقسمة على 1 متبوعًا ب 3 أصفار
1e-3 = 1 / 1000 (=0.001)

// بالقسمة على 1 متبوعًا ب 6 أصفار
1.23e-6 = 1.23 / 1000000 (=0.00000123)
</pre>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة تطوير التطبيقات باستخدام لغة JavaScript
		</p>

		<p class="banner-subtitle">
			تعلم البرمجة بلغة جافا سكريبت انطلاقًا من أبسط المفاهيم وحتى بناء تطبيقات حقيقية.
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/javascript-application-development/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<img alt="دورة تطوير التطبيقات باستخدام لغة JavaScript" src="https://academy.hsoub.com/learn/assets/images/courses/javascript-application-development.png">
	</div>
</div>

<h3>
	الأعداد الست عشرية، والثنائية والثمانية
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_21" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">0xff</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 255</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">0xFF</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 255 (العدد ذاته, لا يوجد اختلاف باختلاف حالة الأحرف)</span></pre>

<p>
	تستخدم الأنظمة الثنائية والثمانية نادرًا، لكنها مدعومة أيضًا باستخدام السابقة <code>0b</code> والسابقة <code>0o</code> على التوالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_23" style=""><span class="pln">let a </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0b11111111</span><span class="pun">;</span><span class="pln"> </span><span class="com">// الهيئة الثنائية لِلعدد 255</span><span class="pln">
let b </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0o377</span><span class="pun">;</span><span class="pln"> </span><span class="com">// الهيئة الثمانية لِلعدد 255</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> a </span><span class="pun">==</span><span class="pln"> b </span><span class="pun">);</span><span class="pln"> </span><span class="com">// صحيح، العدد ذاته 255 في كلا الجانبين</span></pre>

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

<h2>
	toString(base)‎
</h2>

<p>
	يُرجِع التابع <code>num.toString(base)‎</code> تمثيلًا نصيًا للمتغير <code>num</code> إلى النظام العددي المُعطى <code>base</code>. مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_25" style=""><span class="pln">let num </span><span class="pun">=</span><span class="pln"> </span><span class="lit">255</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> num</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">(</span><span class="lit">16</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">  </span><span class="com">// ff</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> num</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">   </span><span class="com">// 11111111</span></pre>

<p>
	يمكن أن تختلف قيمة <code>base</code> من <code>2</code> حتى <code>36</code>، والقيمة الافتراضية هي <code>10</code>.
</p>

<p>
	حالات الاستخدام الشائعة:
</p>

<ul>
	<li>
		<code>base=16</code>: تستخدم للألوان الست عشرية، وتشفير الأحرُف وغيرها، قد تحوي الخانات الأرقام <code>0..9</code> أو الأحرف <code>A..F</code>.
	</li>
	<li>
		<code>base=2</code>: يستخدم بكثرة في تصحيح العمليات الدقيقة، يمكن أن يحوي الرقمين <code>0</code> أو <code>1</code>.
	</li>
	<li>
		<code>base=36</code>: هو الحد الأعلى، يمكن أن يحوي الأرقام <code>0..9</code> أو الأحرُف <code>A..Z</code>. يمكن استخدام جميع الأحرف اللاتينية لتمثيل عدد. قد يبدو أمرًا ممتعًا لكن يكون مفيدًا في حال احتجنا لتحويل معرف عددي طويل إلى عدد أقصر، مثلًا، لتقصير رابط url. يمكن تمثيله بالنظام العددي ذي الأساس <code>36</code>:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_27" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">123456.</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">(</span><span class="lit">36</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2n9c</span></pre>

<h3>
	<strong>نقطتين لِاستدعاء تابع</strong>
</h3>

<p>
	لاحظ أن النقطتين في <code>‎123456..toString(36)‎</code> ليست خطأ كتابي. إن أردنا استدعاء تابع مباشرة على عدد/ مثل التابع <code>toString</code> في المثال أعلاه، فسنحتاج إلى نقطتين بعد العدد <code>..</code>.
</p>

<p>
	إن وضعنا نقطة واحدة فقط <code>‎123456.toString(36)‎</code> فسيكون هناك خطأ، لأن JavaScript سَتعتبر أن النقطة هي فاصلة عشرية وأن ما بعدها هو جزء عشري للعدد. فإذا وضعنا نقطة أخرى فستعرف أن الجزء العشري فارغ وتنتقل إلى الدالة.
</p>

<p>
	يمكن كتابتها بهذه الطريقة أيضًا <code>‎(123456).toString(36)‎</code>.
</p>

<h2>
	التقريب (Rounding)
</h2>

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

<ul>
	<li>
		<code>Math.floor</code>: تقريب للجزء الأصغر: <code>3.1</code> تصبح <code>3</code>، و <code>-1.1</code> تصبح <code>-2</code>.
	</li>
	<li>
		<code>Math.ceil</code>: تقريب للجزء الأكبر: <code>3.1</code> تصبح <code>4</code>، و <code>-1.1</code> تصبح <code>-1</code>.
	</li>
	<li>
		<code>Math.round</code>: تقريب لأقرب عدد صحيح: <code>3.1</code> تصبح <code>3</code>، <code>3.6</code> تصبح <code>4</code> و <code>-1.1</code> تصبح <code>-1</code>.
	</li>
	<li>
		<code>Math.trunc</code> <strong>(ليست مدعومة بواسطة المتصفح Internet Explorer)</strong>: تحذف أي شيء بعد الفاصلة العشرية بدون تقريب: <code>3.1</code> تصبح <code>3</code>، -<code>1.1</code> تصبح <code>-1</code>.
	</li>
</ul>

<p>
	يختصر الجدول في الأسفل الاختلافات بين هذه التوابع:
</p>

<table>
	<thead>
		<tr>
			<th>
				 
			</th>
			<th>
				<code>Math.floor</code>
			</th>
			<th>
				<code>Math.ceil</code>
			</th>
			<th>
				<code>Math.round</code>
			</th>
			<th>
				<code>Math.trunc</code>
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				3.1
			</td>
			<td>
				3
			</td>
			<td>
				4
			</td>
			<td>
				3
			</td>
			<td>
				3
			</td>
		</tr>
		<tr>
			<td>
				3.6
			</td>
			<td>
				3
			</td>
			<td>
				4
			</td>
			<td>
				4
			</td>
			<td>
				3
			</td>
		</tr>
		<tr>
			<td>
				-1.1
			</td>
			<td>
				-2
			</td>
			<td>
				-1
			</td>
			<td>
				-1
			</td>
			<td>
				-1
			</td>
		</tr>
		<tr>
			<td>
				-1.6
			</td>
			<td>
				-2
			</td>
			<td>
				-1
			</td>
			<td>
				-2
			</td>
			<td>
				-1
			</td>
		</tr>
	</tbody>
</table>

<p>
	تُعَطِّي هذه التوابع جميع الاحتمالات الممكنة للتعامل مع الجزء العشري للعدد، لكن ماذا إن كنا نريد تقريب العدد إلى خانة محدَّدة بعد الفاصلة العشرية؟
</p>

<p>
	مثلًا، لدينا العدد <code>1.2345</code> ونريد تقريب إلى خانتين لنحصل على <code>1.23</code> فقط. يوجد طريقتين للقيام بذلك:
</p>

<p>
	1- الضرب والقسمة: مثلًا، لتقريب الرقم إلى الخانة الثانية بعد الفاصلة العشرية، يمكننا ضرب العدد في <code>100</code>، ثم نستدعي تابع التقريب ثم نقسم على نفس العدد.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_29" style=""><span class="pln">let num </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1.23456</span><span class="pun">;</span><span class="pln">

alert</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="pln">num </span><span class="pun">*</span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1.23456 -&gt; 123.456 -&gt; 123 -&gt; 1.23</span></pre>

<p>
	2- يقرب التابع <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed" rel="external nofollow"><code>toFixed(n)</code></a><code>‎</code> العدد المستدعى معه إلى الخانة <code>n</code> بعد الفاصلة العشرية ويُرجِع تمثيلًا نصيًا للنتيجة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_31" style=""><span class="pln">let num </span><span class="pun">=</span><span class="pln"> </span><span class="lit">12.34</span><span class="pun">;</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> num</span><span class="pun">.</span><span class="pln">toFixed</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"> </span><span class="com">// "12.3"</span></pre>

<p>
	يعمل التابع على تقريب العدد للأكبر أو الأصغر وفقًا إلى أقرب قيمة، مثل التابع <code>Math.round</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_33" style=""><span class="pln">let num </span><span class="pun">=</span><span class="pln"> </span><span class="lit">12.36</span><span class="pun">;</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> num</span><span class="pun">.</span><span class="pln">toFixed</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"> </span><span class="com">// "12.4"</span></pre>

<p>
	لاحظ أن مخرجات التابع <code>toFixed</code> هي نص. إن كان الجزء العشري أقل من المطلوب، تُضاف الأصفار إلى نهاية الرقم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_35" style=""><span class="pln">let num </span><span class="pun">=</span><span class="pln"> </span><span class="lit">12.34</span><span class="pun">;</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> num</span><span class="pun">.</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "12.34000", أصفار مضافة لجعل عدد الخانات 5</span></pre>

<p>
	يمكننا تحويل المخرجات إلى عدد باستخدام الجمع الأحادي أو باستدعاء الدالة <code>Number()</code>: <code>+num.toFixed(5)‎</code>.
</p>

<h2>
	حسابات غير دقيقة
</h2>

<p>
	يُمَثَّل العدد داخليًا بصيغة 64-بِت <a href="https://en.wikipedia.org/wiki/IEEE_754-2008_revision" rel="external nofollow">IEEE-754</a>، لذا يوجد 64 بِت لتخزين العدد: تستخدم 52 منها لتخزين أرقام العدد، و 11 منها لتخزين مكان الفاصلة العشرية (تكون أصفارًا للاعداد الصحيحة)، و 1 بِت لإشارة العدد.
</p>

<p>
	إن كان العدد كبيرًا جدًا، فَسيزداد عن مساحة التخزين 64-بِت، معطيًا ما لا نهاية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_37" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">1e500</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ما لا نهاية</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_39" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">0.1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0.2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0.3</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// خطأ</span></pre>

<p>
	الجملة السابقة تحدث فعليًا، إن فحصنا ما إن كان مجموع <code>0.1</code> و <code>0.2</code> هو <code>0.3</code>، نحصل على <code>false</code>. غريب أليس كذلك؟! ما النتيجة إذًا إن لم تكن <code>0.3</code>؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_41" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">0.1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0.2</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0.30000000000000004</span></pre>

<p>
	يوجد خطأ آخر هنا غير الموازنة الخطأ. تخيل أننا نقوم بموقع للتسوق الالكتروني، ووضع الزائر بضائع بقيم <code>$0.10</code> و <code>$0.20</code> في السلة. سيكون مجموع الطلب <code>$0.30000000000000004</code>. مما قد يفاجئ أي أحد.
</p>

<p>
	لكن السؤال الأهم، لم يحدث هذا؟
</p>

<p>
	يُخَزَّن العدد في الذاكرة بهيئته الثنائية، سلسلة من البِت - واحدات وأصفار. لكن الأجزاء مثل <code>0.1</code> و <code>0.2</code> والتي تبدو بسيطة بالنسبة للنظام العددي العشري هي في الحقيقة أجزاء غير منتهية في النظام الثنائي.
</p>

<p>
	بمعنى آخر، ما هو <code>0.1</code>؟ هو واحد مقسوم على عشرة <code>1/10</code>، عُشر. ويكون من السهل تمثيلة بنظام الأعداد العشري. موازنة بالثلث: <code>1/3</code>. الذي يصبح بكسور غير منتهية <code>‎0.33333(3)‎</code>.
</p>

<p>
	لذا، فإن من المؤكد أن تعمل الأعداد المقسومة على مضاعفات العدد <code>10</code> في النظام العشري، ولا تعمل المقسومة على <code>3</code>. وكذلك أيضًا في النظام الثنائي، تعمل الأعداد المقسومة على مضاعفات العدد <code>2</code>، لكن يصبح العدد <code>1/10</code> كسورًا ثنائية غير منتهية.
</p>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_43" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">0.1</span><span class="pun">.</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0.10000000000000000555</span></pre>

<p>
	وعند جمع عددين، فإن الأجزاء المفقودة تظهر.
</p>

<p>
	هذا يفسر لِمَ <code>0.1 + 0.2</code> لا تساوي <code>0.3</code> بالضبط.
</p>

<h3>
	<strong>ليس فقط في JavaScript</strong>
</h3>

<p>
	هذه المشكلة موجودة في العديد من اللغات البرمجية الأخرى مثل <a href="https://wiki.hsoub.com/PHP" rel="external">PHP</a>، و Java، و C، و Perl، و <a href="https://wiki.hsoub.com/Ruby" rel="external">Ruby</a> تُعطي النتيجة ذاتها، لأنها تعتمد على الصيغة العددية ذاتها.
</p>

<p>
	هل يمكننا تجنب المشكلة؟ بالطبع، أفضل طريقة هي بتقريب النتيجة بمساعدة التابع <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed" rel="external nofollow">toFixed(n)</a><code>‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_45" style=""><span class="pln">let sum </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0.2</span><span class="pun">;</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> sum</span><span class="pun">.</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0.30</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_47" style=""><span class="pln">let sum </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0.2</span><span class="pun">;</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">+</span><span class="pln">sum</span><span class="pun">.</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0.3</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_49" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0.1</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">0.2</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0.3</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0.28</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"> </span><span class="lit">0.14</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 0.4200000000000001</span></pre>

<p>
	لذا، يقلل نهج الضرب والقسمة الخطأ لكنه لا يزيلة كليًا.
</p>

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

<h3>
	<strong>شر البلية ما يضحك</strong>
</h3>

<p>
	جرب تشغيل ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_51" style=""><span class="com">// مرحبًا! أنا عدد يزداد من تلقاء نفسه!</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">9999999999999999</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// يظهر 10000000000000000</span></pre>

<p>
	هذه الحالة تعاني من المشكلة ذاتها: ضياع الدقة. يوجد 64 بِت للعدد، يمكن استخدام 52 منها لتخزين العدد، لكنها غير كافية. لذا يظهر الرقم الأخير.
</p>

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

<h3>
	<strong>صفران</strong>
</h3>

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

<p>
	لا يكون هذا الفرق ملحوظًا في أغلب الحالات، لأن المعامِلات مُعَدَّة لتعاملهما كعدد واحد.
</p>

<h2>
	الفحص: isFinite و isNaN
</h2>

<p>
	هل تذكر القيم العددية الخاصة التالية؟
</p>

<ul>
	<li>
		<code>Infinity</code> (و <code>‎-Infinity</code>) هي قيمة عددية خاصة تكون أكبر أو أصغر من أي شيء.
	</li>
	<li>
		<code>NaN</code> تُمَثِّل وجود خطأ (ليس عددًا Not a Number).
	</li>
</ul>

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

<ul>
	<li>
		<code>isNaN(value)‎</code> يُحوِّل المُعامل إلى عدد ثم يفحص ما إن كان <code>NaN</code>:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_53" style=""><span class="pln">alert</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="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> isNaN</span><span class="pun">(</span><span class="str">"str"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_55" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </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="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// false</span></pre>

<ul>
	<li>
		<code>isFinite(value)‎</code> يُحوِّل مُعامله إلى عدد ويُرجِع القيمة <code>true</code> إن كان عددًا عاديًا، أي لا يكون <code>NaN</code> أو <code>Infinity</code> أو <code>‎-Infinity</code>:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_57" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> isFinite</span><span class="pun">(</span><span class="str">"15"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> isFinite</span><span class="pun">(</span><span class="str">"str"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// false, NaN</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> isFinite</span><span class="pun">(</span><span class="kwd">Infinity</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// false, Infinity</span></pre>

<p>
	تستخدم <code>isFinite</code> أحيانًا للتحقق ما إن كان النص عددًا عاديًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_59" style=""><span class="pln">let num </span><span class="pun">=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">prompt</span><span class="pun">(</span><span class="str">"Enter a number"</span><span class="pun">,</span><span class="pln"> </span><span class="str">''</span><span class="pun">);</span><span class="pln">

</span><span class="com">// أو قيمة غير عددية -Infinity أو Infinity سيكون صحيحًا إلا إن أدخلت</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> isFinite</span><span class="pun">(</span><span class="pln">num</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	يرجى ملاحظة أن الفراغ أو المسافة الواحدة تُعامل معاملة الصفر <code>0</code> في جميع التوابع العددية بما فيها <code>isFinite</code>.
</p>

<h3>
	<strong>الموازنة باستخدام <code>Object.is</code></strong>
</h3>

<p>
	يوجد تابع خاص مدمج في اللغة يدعى <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" rel="external nofollow"><code>Object.is</code></a> يوزان القيم كما <code>===</code> لكنه أكثر موثوقية لسببين:
</p>

<ol>
	<li>
		أنه يعمل مع <code>NaN</code>: أي "<code>Object.is(NaN, NaN) === true"</code> وهذا أمر جيد.
	</li>
	<li>
		القيمتان <code>0</code> و <code>-0</code> مختلفتان: "<code>Object.is(0, -0) === false"</code>، الأمر صحيح تقنيًا، لأن العدد لديه إشارة داخليًا مما يجعل القيم مختلفة حتى لو كانت باقي الخانات أصفارًا.
	</li>
</ol>

<p>
	يكون التابع <code>Object.is(a, b)‎</code> نفس <code>a === b</code> في باقي الحالات.
</p>

<p>
	تُستخدم طريقة الموازنة هذه غالبًا في توصيف JavaScript. عندما تحتاج خوارزمية لموازنة كون قيمتين متطابقتان تمامًا فإنها تستخدم <code>Object.is</code> (تُسَمَّى داخليًا القيمة ذاتها "<a href="https://tc39.github.io/ecma262/#sec-samevalue" rel="external nofollow">SameValue</a>").
</p>

<h2>
	parseInt و parseFloat
</h2>

<p>
	التحويل العددي باستخدام الجمع <code>+</code> أو <code>Number()‎</code> يعد صارمًا. إن لم تكن القيمة عددًا فإنها تفشل:
</p>

<pre class="ipsCode">alert( +"100px" ); // NaN
</pre>

<p>
	الاستثناء الوحيد هو المسافات الفارغة ببداية أو نهاية النص، إذ يتم تجاهلها.
</p>

<p>
	لكن، يوجد لدينا في الواقع قيمًا بالوحدات، مثل <code>"100px"</code> أو <code>"12pt"</code> في CSS. في العديد من الدول أيضا، يُلحَق رمز العملة بالقيمة، فمثًلا، لدينا <code>"19€"</code> ونريد استخراج قيمة عددية من ذلك. هذا ما يقوم به التابعان <code>parseInt</code> و <code>parseFloat</code>، إذ يقرآن العدد من النص المعطى حتى تعجزان على ذلك فتتوقف العملية. في حال وجود خطأ، يعيدان العدد المُجَمَّع. فيعيد التابع <code>parseInt</code> عددًا صحيحًا، بينما يعيد التابع <code>parseFloat</code> عددًا عشريًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_61" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> parseInt</span><span class="pun">(</span><span class="str">'100px'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 100</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> parseFloat</span><span class="pun">(</span><span class="str">'12.5em'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 12.5</span><span class="pln">

</span><span class="com">// يُرجَع العدد الصحيح فقط</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> parseInt</span><span class="pun">(</span><span class="str">'12.3'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 12</span><span class="pln">

</span><span class="com">// تُوقِف النقطة الثانية عملية التحليل</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> parseFloat</span><span class="pun">(</span><span class="str">'12.3.4'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 12.3</span></pre>

<p>
	يوجد بعض الحالات يرجع فيها التابع <code>parseInt</code> أو <code>parseFloat</code> القيمة <code>NaN</code> وذلك عندما لا يوجد أي رقم لإرجاعه. ففي المثال التالي، يوقف الحرف الأول العملية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_63" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> parseInt</span><span class="pun">(</span><span class="str">'a123'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// NaN</span></pre>

<h3>
	<strong>المُعامِل الثاني للتابع <code>parseInt(str, radix)‎</code></strong>
</h3>

<p>
	لدى التابع <code>parseInt()‎</code> مُعامِل ثانٍ اختياري. والذي يحدد نوع النظام العددي، لذا يمكن للتابع <code>parseInt</code> تحويل النصوص ذات الأعداد الست عشرية، الثنائية وهكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_65" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> parseInt</span><span class="pun">(</span><span class="str">'0xff'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 255</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> parseInt</span><span class="pun">(</span><span class="str">'ff'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 255</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> parseInt</span><span class="pun">(</span><span class="str">'2n9c'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">36</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 123456</span></pre>

<h2>
	دوال رياضية أخرى
</h2>

<p>
	تحتوي JavaScript على الكائن المُدمَج <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math" rel="external nofollow">Math</a> الذي يحتوي على مكتبة صغيرة بالدوال والثوابت الرياضية. إليك بعض الأمثلة:
</p>

<ul>
	<li>
		<strong><code>Math.random()‎</code></strong>: تُرجِع عددًا عشوائيًا من 0 إلى 1 (لا تتضمن 1):
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_67" style=""><span class="pln">alert</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="pun">);</span><span class="pln">  </span><span class="com">// 0.1234567894322</span><span class="pln">
alert</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="pun">);</span><span class="pln">  </span><span class="com">// 0.5435252343232</span><span class="pln">
alert</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="pun">);</span><span class="pln">  </span><span class="com">// ... (أي رقم عشوائي)</span></pre>

<ul>
	<li>
		<strong><code>Math.max(a, b, c...)</code> <code>/</code> <code>Math.min(a, b, c...)‎</code></strong>: تُرجِع القيمة الأكبر أو الأصغر من المُعامِلات:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_69" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="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="pun">-</span><span class="lit">10</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">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</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="pun">);</span><span class="pln"> </span><span class="com">// 1</span></pre>

<ul>
	<li>
		<strong><code>Math.pow(n, power)‎</code></strong>: تُرجع العدد <code>n</code> مرفوعًا إلى الأُس المُعطى:
	</li>
</ul>

<pre class="ipsCode">alert( Math.pow(2, 10) ); // 2^10 = 1024
</pre>

<p>
	يوجد المزيد من الدوال والثوابت في الكائن <code>Math</code>، بما فيها علم المُثَلَّثات، والتي يمكنك ايجادها في <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math" rel="external nofollow">توثيق الكائن Math</a>.
</p>

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

<p>
	لكتابة أعداد كبيرة:
</p>

<ul>
	<li>
		أضِف <code>"e"</code> مع عدد الأصفار الخاصة بالعدد المطلوب، مثل: <code>123e6</code> هو <code>123</code> مع 6 أصفار.
	</li>
	<li>
		قيمة سالبة بعد <code>"e"</code> تقسم العدد على 1 مع عدد الأصفار المُعطى.
	</li>
</ul>

<p>
	لِأنظمة العد المختلفة:
</p>

<ul>
	<li>
		يمكن كتابة الأعداد مباشرة بالنظام الستعشري (<code>0x</code>)، أو الثُماني (<code>0o</code>)، أو الثُنائي (<code>0b</code>).
	</li>
	<li>
		<code>parseInt(str, base)‎</code> تحوِّل النص <code>str</code> إلى عدد صحيح بالنظام العددي المُعطى <code>base</code>، و <code>‎2 ≤ base ≤ 36</code>.
	</li>
	<li>
		<code>num.toString(base)‎</code> تحوِّل العدد إلى نص بالنظام العددي المُعطى <code>base</code>.
	</li>
</ul>

<p>
	لتحويل القيم مثل <code>12pt</code> and <code>100px</code> إلى عدد:
</p>

<ul>
	<li>
		استخدم <code>parseInt</code> أو <code>parseFloat</code> لتحويل سلس، والتي تقرأ العدد من نص وتُرجِع القيمة التي استطاعت قرائتها قبل حصول أي خطأ.
	</li>
</ul>

<p>
	للأجزاء:
</p>

<ul>
	<li>
		التقريب باستخدام <code>Math.floor</code>، أو <code>Math.ceil</code>، أو <code>Math.trunc</code>، أو <code>Math.round</code> أو <code>num.toFixed(precision)‎</code>.
	</li>
	<li>
		تذكر وجود ضياع في دقة الجزء العشري عند التعامل مع الكسور.
	</li>
</ul>

<p>
	للمزيد من الدوال الرياضية:
</p>

<ul>
	<li>
		اطلع على الكائن <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math" rel="external nofollow">Math</a> عندما تحتاج ذلك، هذه المكتبة صغيرة جدًا، لكنها تغطي الاحتياجات الأساسية.
	</li>
</ul>

<h2>
	المهام
</h2>

<h3>
	جمع الأعداد من الزائر
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

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

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_71" style=""><span class="pln">let a </span><span class="pun">=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">prompt</span><span class="pun">(</span><span class="str">"The first number?"</span><span class="pun">,</span><span class="pln"> </span><span class="str">""</span><span class="pun">);</span><span class="pln">
let b </span><span class="pun">=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">prompt</span><span class="pun">(</span><span class="str">"The second number?"</span><span class="pun">,</span><span class="pln"> </span><span class="str">""</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b </span><span class="pun">);</span></pre>

	<p>
		لاحظ عامل الجمع الأحادي <code>+</code> قبل <code>prompt</code>. يحوِّل القيم إلى أعداد. وإلا فإن <code>a</code> و <code>b</code> ستكون نصوصًا وسيكون مجموعهما بدمجهما: <code>"1" + "2" = "12"</code>.
	</p>
</div>

<h3>
	لماذا ‎6.35.toFixed(1) == 6.3؟
</h3>

<p class="task__importance">
	الأهمية: 4
</p>

<p>
	تُدَوِّر كلًا من <code>Math.round</code> و <code>toFixed</code> العدد إلى أقرب عدد له وفقًا للتوثيق: الأجزاء من <code>0..4</code> تُدَوَّر للأسفل، بينما الأجزاء <code>5..9</code> تثدَوَّر للأعلى.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_73" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">1.35</span><span class="pun">.</span><span class="pln">toFixed</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"> </span><span class="com">// 1.4</span></pre>

<p>
	في المثال المشابه أدناه، لِمَ تُدَوَّر <code>6.35</code> إلى <code>6.3</code>، وليس <code>6.4</code>؟
</p>

<pre class="ipsCode">alert( 6.35.toFixed(1) ); // 6.3
</pre>

<p>
	كيف نُدَوِّر <code>6.35</code> بالطريقة الصحيحة؟
</p>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<p>
		الجزء <code>6.35</code> هو عبارة عن عدد غير منتهي في الصيغة الثنائية. وكجميع الحالات المشابهة، يُخَزَّن مع ضياع في الدقة. لنرَ:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_75" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">6.35</span><span class="pun">.</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 6.34999999999999964473</span></pre>

	<p>
		قد يتسبب ضياع الدقة في زيادة أو نقصان أي عدد. يكون العدد في هذه الحالة أقل بقليل من قيمته الفعلية، ولهذا يُدَوَّر للأسفل. ماذا عن العدد <code>1.35</code>؟
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_77" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="lit">1.35</span><span class="pun">.</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1.35000000000000008882</span></pre>

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

	<p>
		<strong>كيف يمكننا حل مشكلة تقريب العدد <code>6.35</code> حتى يُدَوَّر بالشكل الصحيح</strong>
	</p>

	<p>
		يجب أن نحوله إلى عدد صحيح قبل التقريب:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_79" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">(</span><span class="lit">6.35</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">10</span><span class="pun">).</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 63.50000000000000000000</span></pre>

	<p>
		لاحظ عدم وجود أي ضياع في دقة العدد <code>63.5</code>. ذلك لأن الجزء العشري <code>0.5</code> يساوي <code>1/2</code>. يمكن تمثيل الأجزاء المقسومة على <code>2</code> تُمَثَّل بشكل صحيح في النظام الثنائي. يمكننا تقريب العدد الآن:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_81" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">round</span><span class="pun">(</span><span class="lit">6.35</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 6.35 -&gt; 63.5 -&gt; 64(rounded) -&gt; 6.4</span></pre>
</div>

<h3>
	كرر حتى يصبح المُدخَل عددًا
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	أنشِئ الدالة <code>readNumber</code> والتي تطلب من الزائر إدخال عدد حتى يقوم بإدخال قيمة عددية صحيحة. يجب أن تكون القيمة المُرجَعة عددًا.
</p>

<p>
	يمكن للزائر إيقاف العملية بإدخال سطر فارغ أو الضغط على "CANCEL". يجب أن تُرجِع الدالة <code>null</code> في هذه الحالة.
</p>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_83" style=""><span class="kwd">function</span><span class="pln"> readNumber</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let num</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">
    num </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"Enter a number please?"</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">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isFinite</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">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> num </span><span class="pun">===</span><span class="pln"> </span><span class="str">''</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</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">num</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">Read</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">readNumber</span><span class="pun">()}`);</span></pre>

	<p>
		طريقة الحل معقدة قليلًا حتى نتمكن من معالجة حالات الأسطر الفارغة/<code>null</code>. لذا فإن الشيفرة تستقبل المدخلات حتى تكون عددًا عاديًا. تُطَبِّق كلًا من <code>null</code> (cancel)‎ والسطر الفارغ شروط الأعداد كونها تساوي القيمة العددية <code>0</code>.
	</p>

	<p>
		بعد توقف الشيفرة يجب معاملة <code>null</code> والأسطر الفارغة بطريقة خاصة (إرجاع <code>null</code>). لأن تحويلها إلى أعداد يُرجِع <code>0</code>.
	</p>
</div>

<h3>
	حلقة غير منتهية أحيانًا
</h3>

<p class="task__importance">
	الأهمية: 4
</p>

<p>
	الحلقة التالية غير منتهية، ولا تتوقف أبدًا. لماذا؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_85" style=""><span class="pln">let i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  i </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">0.2</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<p>
		ذلك لأن <code>i</code> لن يساوي <code>10</code> أبدًا. نفذ الشيفرة التالية لرؤية قيم <code>i</code>:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_87" style=""><span class="pln">let i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">11</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  i </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">0.2</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">9.8</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10.2</span><span class="pun">)</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln"> i </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<h3>
	رقم عشوائي من العدد الأدنى إلى الأقصى
</h3>

<p class="task__importance">
	الأهمية: 2
</p>

<p>
	تُنشِئ الدالة <code>Math.random()‎</code> المُضَمَنَة في اللغة قيمة عشوائية بين <code>0</code> و <code>1</code> (ليس بما في ذلك <code>1</code>). اكتب الدالة <code>random(min, max)‎</code> لتوليد عدد عشري عشوائي من <code>min</code> إلى <code>max</code> (بما لا يتضمن <code>max</code>).
</p>

<p>
	أمثلة عن عملها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_89" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> random</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1.2345623452</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> random</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3.7894332423</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> random</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 4.3435234525</span></pre>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<p>
		نريد تعيين جميع القيم من الفترة 0…1 إلى القيم من <code>min</code> إلى <code>max</code>. يمكن القيام بذلك في مرحلتين:
	</p>

	<ol>
		<li>
			إذا ضربنا قيمة عشوائية من 0…1 في <code>max-min</code>. فإن فترة القيم الممكنة تزيد <code>0..1</code> إلى <code>0..max-min</code>.
		</li>
		<li>
			إذا أضفنا <code>min</code> الآن، تصبح الفترة من <code>min</code> إلى <code>max</code>.
		</li>
	</ol>

	<p>
		الدالة:
	</p>

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

alert</span><span class="pun">(</span><span class="pln"> random</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> random</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> random</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span></pre>
</div>

<h3>
	قيمة صحيحة عشوائية من min إلى max
</h3>

<p class="task__importance">
	الأهمية: 2
</p>

<p>
	أنشِئ دالة <code>randomInteger(min, max)‎</code> تقوم بتوليد قيمة صحيحة عشوائية من <code>min</code> إلى <code>max</code> بما في ذلك <code>min</code> و <code>max</code>.
</p>

<p>
	يجب أن يظهر كل رقم من الفترة <code>min..max</code> بفرص متساوية. مثال على طريقة العمل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_93" style=""><span class="pln">alert</span><span class="pun">(</span><span class="pln"> randomInteger</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> randomInteger</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> randomInteger</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5</span></pre>

<p>
	يمكنك استخدام حل المثال السابق كأساس لهذه المهمة.
</p>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<p>
		<strong>الطريقة السهلة والخطأ</strong>
	</p>

	<p>
		الحل الأسهل لكنه خطأ سيكون بتوليد قيمة من <code>min</code> إلى <code>max</code> وتقريبها:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_95" style=""><span class="kwd">function</span><span class="pln"> randomInteger</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">
  let rand </span><span class="pun">=</span><span class="pln"> min </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="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="kwd">return</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">round</span><span class="pun">(</span><span class="pln">rand</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> randomInteger</span><span class="pun">(</span><span class="lit">1</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></pre>

	<p>
		الدالة تعمل لكنها خطأ. احتمال ظهور القيم الطرفية <code>min</code> و <code>max</code> أقل بمرتين من باقي القيم. إن شغلنا المثال أعلاه لعدة مرات، فينرى ظهور <code>2</code> بصورة أكبر.
	</p>

	<p>
		يحدث ذلك لأن <code>Math.round()‎</code> تأخذ رقما من الفترة <code>1..3</code> وتُدَوِرها كما يلي:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_97" style=""><span class="pln">values from </span><span class="lit">1</span><span class="pln">    </span><span class="pun">...</span><span class="pln"> to </span><span class="lit">1.4999999999</span><span class="pln">  become </span><span class="lit">1</span><span class="pln">
values from </span><span class="lit">1.5</span><span class="pln">  </span><span class="pun">...</span><span class="pln"> to </span><span class="lit">2.4999999999</span><span class="pln">  become </span><span class="lit">2</span><span class="pln">
values from </span><span class="lit">2.5</span><span class="pln">  </span><span class="pun">...</span><span class="pln"> to </span><span class="lit">2.9999999999</span><span class="pln">  become </span><span class="lit">3</span></pre>

	<p>
		نلاحظ الآن أن لدى <code>1</code> قيم أقل بمرتين من <code>2</code> وكذلك <code>3</code>.
	</p>

	<div class="banner-container ipsBox ipsPadding">
		<div class="inner-banner-container">
			<p class="banner-heading">
				دورة تطوير التطبيقات باستخدام لغة JavaScript
			</p>

			<p class="banner-subtitle">
				تعلم البرمجة بلغة جافا سكريبت انطلاقًا من أبسط المفاهيم وحتى بناء تطبيقات حقيقية.
			</p>

			<div>
				<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/javascript-application-development/" rel="">اشترك الآن</a>
			</div>
		</div>

		<div class="banner-img">
			<img alt="دورة تطوير التطبيقات باستخدام لغة JavaScript" src="https://academy.hsoub.com/learn/assets/images/courses/javascript-application-development.png">
		</div>
	</div>

	<p>
		<strong>الطريقة الصحيحة</strong>
	</p>

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

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_99" style=""><span class="kwd">function</span><span class="pln"> randomInteger</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="com">// (max+0.5) إلى (min-0.5) التقريب الآن من</span><span class="pln">
  let rand </span><span class="pun">=</span><span class="pln"> min </span><span class="pun">-</span><span class="pln"> </span><span class="lit">0.5</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">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="kwd">return</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">round</span><span class="pun">(</span><span class="pln">rand</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> randomInteger</span><span class="pun">(</span><span class="lit">1</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></pre>

	<p>
		طريقة بديلة هي استخدام الدالة <code>Math.floor</code> لرقم عشوائي من <code>min</code> إلى <code>max+1</code>:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_101" style=""><span class="kwd">function</span><span class="pln"> randomInteger</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="com">// (max+1) إلى min التقريب الآن من </span><span class="pln">
  let rand </span><span class="pun">=</span><span class="pln"> min </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="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="lit">1</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> min</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="pln">rand</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> randomInteger</span><span class="pun">(</span><span class="lit">1</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></pre>

	<p>
		جميع الفترات أصبحت متوازنة الآن:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_687_103" style=""><span class="pln">values from </span><span class="lit">1</span><span class="pln">  </span><span class="pun">...</span><span class="pln"> to </span><span class="lit">1.9999999999</span><span class="pln">  become </span><span class="lit">1</span><span class="pln">
values from </span><span class="lit">2</span><span class="pln">  </span><span class="pun">...</span><span class="pln"> to </span><span class="lit">2.9999999999</span><span class="pln">  become </span><span class="lit">2</span><span class="pln">
values from </span><span class="lit">3</span><span class="pln">  </span><span class="pun">...</span><span class="pln"> to </span><span class="lit">3.9999999999</span><span class="pln">  become </span><span class="lit">3</span></pre>

	<p>
		لدى جميع الفترات الطول ذاته مما يجعل التوزيع النهائي موحدًا.
	</p>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/number" rel="external nofollow">Numbers</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript Language</a>
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
}

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
	<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-r817/" rel="">السلاسل النصية (strings)</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-r815/" rel="">توابع الأنواع الأولية</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">816</guid><pubDate>Thu, 27 Feb 2020 13:02:00 +0000</pubDate></item><item><title>&#x62A;&#x648;&#x627;&#x628;&#x639; &#x627;&#x644;&#x623;&#x646;&#x648;&#x627;&#x639; &#x627;&#x644;&#x623;&#x648;&#x644;&#x64A;&#x629; (primitives methods) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#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%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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/32.jpg.adbcf2178f1f949bc21bd311ce4e49b7.jpg" /></p>

<p>
	تتيح لنا JavaScript التعامل مع أنواع البيانات الأولية (النصوص، الأرقام، وغيرها) كما لو أنها كائنات، كما تزودنا بتوابع (methods) لاستدعائها كما الكائنات. وسندرس هذه التوابع قريبًا، لكن لنرى أولًا كيف تعمل لأن الأنواع الأولية (primitives) ليست كائنات (أي object) وسنجعل الأمر واضحًا هنا.
</p>

<p>
	لنرى إلى الفروق الأساسية بين الأنواع الأولية والكائنات.
</p>

<p>
	النوع الأولي:
</p>

<ul>
<li>
		هو قيمة من نوع أولي (primitive type).
	</li>
	<li>
		يوجد 6 أنواع أولية: نص <code>string</code>، رقم <code>number</code>، قيمة منطقية <code>boolean</code>، رمز <code>symbol</code>، قيمة فارغة <code>null</code> ، وقيمة غير معرفة <code>undefined</code>.
	</li>
</ul>
<p>
	الكائن:
</p>

<ul>
<li>
		قادر على تخزين العديد من القيم ضمن خاصيات.
	</li>
	<li>
		يمكن إنشاؤه باستخدام <code>{}</code>، مثلًا: <code>{name: "John", age: 30}</code>. يوجد أنواع أخرى من الكائنات في JavaScript: مثلا، تعد الدوال كائنات.
	</li>
</ul>
<p>
	أحد أفضل الأشياء بالنسبة للكائنات هو إمكانية تخزين دالة في خاصية من خواص هذا الكائن.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5162_7" style="">
<span class="pln">let john </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">"John"</span><span class="pun">,</span><span class="pln">
  sayHi</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">
    alert</span><span class="pun">(</span><span class="str">"Hi buddy!"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

john</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Hi buddy!</span></pre>

<p>
	إذًا، أنشأنا الكائن <code>john</code> محتويًا الدالة <code>sayHi</code>.
</p>

<p>
	يوجد العديد من الكائنات المدمجة في اللغة، مثل التي تتعامل مع التواريخ، الأخطاء، عناصر HTML، وغيرها. ولديها خاصيات وتوابع مختلفة. لكن لهذه الميزات ثمن!
</p>

<p>
	الكائنات أثقل من المتغيرات الأولية، فهي تتطلب موارد (resources) أكثر لدعم آليتها الداخلية.
</p>

<h2>
	نوع أولي مثل كائن
</h2>

<p>
	هنا نجد التناقض الذي واجهه مُنشِئ JavaScript:
</p>

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

<ol>
<li>
		تبقى المتغيرات الأولية كما هي، قيمة واحدة مثل المطلوب.
	</li>
	<li>
		تتيح لنا اللغة الوصول إلى توابع وخاصيات النصوص، الأرقام، القيم المنطقية، والرموز.
	</li>
	<li>
		حتى يعمل ذلك، يُنشَأ «كائن مغلِّف» (object wrapper) خاص يزود المتغيرات بالوظائف الإضافية، ثم يُدَمَّر.
	</li>
</ol>
<p>
	يختلف الكائن المغلِّف "object wrappers" من نوع أولي لآخر ويُسمَى: <code>String</code>، و <code>Number</code>، و <code>Boolean</code>، و <code>Symbol</code>، لذا فإنه يزود كل نوع بمجموعة مختلفة من التوابع الخاصة به.
</p>

<p>
	مثلا، يوجد دالة للنصوص <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase" rel="external nofollow"><code>str.toUpperCase()</code></a><code>‎</code> والتي تُرجِع النص <code>str</code> بأحرف كبيرة.
</p>

<p>
	آلية عملها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5162_9" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">toUpperCase</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// HELLO</span></pre>

<p>
	الأمر بسيط، أليس كذلك؟ ما يحدث فعلا في الدالة <code>str.toUpperCase()‎</code> هو كالتالي:
</p>

<p>
	1- النص <code>str</code> هو متغير أولي، لذا فعند محاولة الوصول إلى خاصيتِه، يُنشَأ كائن خاص يعرف قيمة النص ويحتوي هذا الكائن على توابع مفيدة من بينها التابع <code>toUpperCase()‎</code>.
</p>

<p>
	2- تعمل هذه الدالة وتُرجِع نصًا جديدًا (يمكن عرضه باستخدام <code>alert</code>).
</p>

<p>
	3- يُدَمَّر الكائن الخاص تاركًا المتغير الأولي <code>str</code>.
</p>

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

<p>
	لدى الأعداد توابع خاصة بها، مثلا، <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed" rel="external nofollow"><code>toFixed(n)</code></a><code>‎</code> تُقرِّب الرقم المُعطَى إلى الدقة المطلوبة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5162_11" style="">
<span class="pln">let n </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1.23456</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1.23</span></pre>

<p>
	سنرى المزيد من التوابع المخصصة في فصل النصوص والأعداد.
</p>

<h3>
	<strong>البانيات <code>String</code> أو <code>Number</code> أو <code>Boolean</code> هي للاستخدام الداخلي فقط</strong>
</h3>

<p>
	تتيح لنا بعض اللغات مثل Java إنشاء كائنات مغلِّفة "wrapper objects" بشكل صريح باستخدام صيغة مثل: <code>new Number(1)‎</code> أو <code>new Boolean(false)‎</code>. ذلك ممكن أيضًا في JavaScript لأسباب تاريخية، لكنه غير مستحسن لأن الأمور قد تسير بشكل خاطئ في العديد من الأماكن.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5162_13" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "number"</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Number</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="com">// "object"!</span></pre>

<p>
	تكون قيمة الكائنات دائمًا <code>true</code> في <code>if</code>، لذا سيتم عرض ما بداخل <code>alert</code> أدناه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5162_15" style="">
<span class="pln">let zero </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="lit">0</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">zero</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// </span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"zero is truthy!?!"</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تقييم قيمة المتغير <code>zero</code> هنا هي القيمة المنطقية <code>true</code>، لأنه كائن.
</p>

<p>
	بالمقابل، من الممكن استخدام التوابع <code>String/Number/Boolean</code> بدون <code>new</code>، إذ تقوم هذه التوابع بتحويل القيمة إلى النوع المقابل: إلى نص، أو رقم، أو قيمة منطقية (أولية).
</p>

<p>
	مثال: الأمر التالي صحيح تمامًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5162_17" style="">
<span class="pln">let num </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="str">"123"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// تحوِّل النص إلى رقم</span></pre>

<h3>
	<strong>ليس لدى القيمتان الأوليتان null/undefined توابعًا</strong>
</h3>

<p>
	النوعان الأوليان <code>null</code> و <code>undefined</code> هما حالة استثناء، فليس لديها كائن مغلِّف (wrapper object) ولا توابع، إذ يعدان من الأنواع الأكثر أولية.
</p>

<p>
	ستتسبب المحاولة في الوصول إلى خاصية بظهور خطأ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5162_19" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">.</span><span class="pln">test</span><span class="pun">);</span><span class="pln"> </span><span class="com">// error</span></pre>

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

<ul>
<li>
		لدى الأنواع الأولية توابع مساعدة عدا <code>null</code> و <code>undefined</code> تسهل التعامل معها، سندرسها في الفصول اللاحقة.
	</li>
	<li>
		تعمل هذه التوابع عبر كائنات مؤقتة، لكن محرك JavaScript مُعد لتحسين العملية داخليًا. لذا فإن استدعاء الكائن لا يتطلب الكثير من الموارد.
	</li>
</ul>
<h2>
	المهام
</h2>

<h3>
	هل من الممكن إضافة خاصية نصية؟
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5162_21" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">

str</span><span class="pun">.</span><span class="pln">test </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">str</span><span class="pun">.</span><span class="pln">test</span><span class="pun">);</span></pre>

<p>
	ماذا تظن؟ هل ستعمل؟ هل ستُعرَض؟
</p>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<p>
		جرب تشغيلها:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5162_23" style="">
<span class="pln">let str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">;</span><span class="pln">

str</span><span class="pun">.</span><span class="pln">test </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">str</span><span class="pun">.</span><span class="pln">test</span><span class="pun">);</span></pre>

	<p>
		يعتمد الأمر على إن كنت تستخدم <code>use strict</code> أم لا، قد تكون النتيجة أحد الخيارين:
	</p>

	<p>
		1- <code>undefined</code> بدون استخدام الوضع الصارم 2- خطأ في الوضع الصارم
	</p>

	<p>
		لماذا؟ لنفكر فيمَ يحصل في السطر <code>(*)</code>:
	</p>

	<p>
		1- يُنشئ "wrapper object" عند محاولة الوصول إلى خاصية للمتغير <code>str</code>.
	</p>

	<p>
		2- الكتابة إلى هذه الخاصية يُعَدُّ خطأ في الوضع الصارم.
	</p>

	<p>
		3- في الحالة الأخرى، تستمر عملية التخزين في الخاصية، يحصل الكائن على الخاصية <code>test</code>. لكن، يُدمَّر الكائن بعد ذلك فلا يصبح لدى <code>str</code> مرجِعًا إليه مما يجعل قيمتها غير معرفة.
	</p>

	<p>
		يوضح هذا المثال أن المتغيرات الأولية ليست كائنات.
	</p>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/primitives-methods" rel="external nofollow">Methods of primitives</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript Language</a>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A3%D8%B9%D8%AF%D8%A7%D8%AF-r816/" rel="">الأعداد</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D8%A7%D9%86%D9%8A-%D9%88%D8%A7%D9%84%D8%B9%D8%A7%D9%85%D9%84-new-r801/" rel="">الباني والعامل "new"</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">815</guid><pubDate>Sun, 23 Feb 2020 14:20:21 +0000</pubDate></item><item><title>&#x627;&#x644;&#x628;&#x627;&#x646;&#x64A; &#x648;&#x627;&#x644;&#x639;&#x627;&#x645;&#x644; "new" &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D8%A7%D9%86%D9%8A-%D9%88%D8%A7%D9%84%D8%B9%D8%A7%D9%85%D9%84-new-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r801/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/IMG_1596.JPG.a85ab5e8cbaa7b98e790d443a40dae27.JPG" /></p>

<p>
	نُنشِئ الكائنات باستخدام الصيغة الاعتيادية المختصرة <code>{...}</code>. لكننا نحتاج لإنشاء العديد من الكائنات المتشابهة غالبًا، مثل العديد من المستخدمين، أو عناصر لقائمة وهكذا. يمكن القيام بذلك باستخدام الدوال البانية (constructor functions) لكائن والمُعامِل <code>"new"</code>.
</p>

<h2>
	الدالة البانية
</h2>

<p>
	تقنيًا، الدوال البانية هي دوال عادية، لكن يوجد فكرتين متفق عليها:
</p>

<ol>
<li>
		أنها تبدأ بأحرف كبيرة.
	</li>
	<li>
		يجب تنفيذها مع المُعامِل <code>"new"</code> فقط.
	</li>
</ol>
<p>
	إليك المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_7" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">User</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">isAdmin </span><span class="pun">=</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">

let user </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="str">"Jack"</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Jack</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">isAdmin</span><span class="pun">);</span><span class="pln"> </span><span class="com">// false</span></pre>

<p>
	عند تنفيذ دالة مع الُعامِل <code>new</code>، تُنَفَّذ الخطوات التالية:
</p>

<ol>
<li>
		يُنشَأ كائن فارغ ويُسنَد إلى <code>this</code>.
	</li>
	<li>
		يُنَفَّذ محتوى الدالة. تقوم غالبًا بتعديل <code>this</code>، وإضافة خاصيات إليه.
	</li>
	<li>
		تُرجَع قيمة <code>this</code>.
	</li>
</ol>
<p>
	بمعنى آخر، تقوم <code>new User(...)‎</code> بشيء يشبه ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_9" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// this = {};  (implicitly)</span><span class="pln">

  </span><span class="com">// this إضافة خاصيات إلى </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">isAdmin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// this;  (implicitly) إرجاع </span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذًا، تُعطي <code>let user = new User("Jack")‎</code> النتيجة التالية ذاتها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_11" style="">
<span class="pln">let user </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">"Jack"</span><span class="pun">,</span><span class="pln">
  isAdmin</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	الآن، إن أردنا إنشاء مستخدمين آخرين، يمكننا استدعاء <code>new User("Ann")‎</code>، و <code>new User("Alice‎")‎</code> وهكذا. تعدُّ هذه الطريقة في بناء الكائنات أقصر من الطريقة الاعتيادية عبر الأقواس فقط، وأيضًا أسهل للقراءة. هذا هو الغرض الرئيسي للبانيات، وهي تطبيق شيفرة قابلة لإعادة الاستخدام لإنشاء الكائنات.
</p>

<p>
	لاحظ أنَّه يمكن استخدام أي دالة لتكون دالة بانية تقنيًا. يعني أنه يمكن تنفيذ أي دالة مع <code>new</code>، وستُنَفَّذ باستخدام الخوارزمية أعلاه. استخدام الأحرف الكبيرة في البداية هو اتفاق شائع لتمييز الدالة البانية من غيرها وأنَّه يجب استدعاؤها مع <code>new</code>.
</p>

<h3>
	<code>new function() { … }‎</code>
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_13" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</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">name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">isAdmin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// ...شيفرة إضافية لإنشاء مستخدم</span><span class="pln">
  </span><span class="com">// ربما منطق معقد أو أي جمل</span><span class="pln">
  </span><span class="com">// متغيرات محلية وهكذا..</span><span class="pln">
</span><span class="pun">};</span></pre>

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

<h2>
	وضع اختبار الباني: <code>new.target</code>
</h2>

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

<p>
	يمكننا فحص ما إن كانت الدالة قد استدعيت باستخدام <code>new</code> أو دونه من داخل الدالة، وذلك باستخدام الخاصية الخاصة <code>new.target</code>.
</p>

<p>
	تكون الخاصية فارغة في الاستدعاءات العادية، وتساوي الدالة البانية إذا استُدعِيَت باستخدام <code>new</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_15" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">User</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="kwd">new</span><span class="pun">.</span><span class="pln">target</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">//  "new" بدون:</span><span class="pln">
</span><span class="typ">User</span><span class="pun">();</span><span class="pln"> </span><span class="com">// undefined</span><span class="pln">

</span><span class="com">// باستخدام "new":</span><span class="pln">
</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">User</span><span class="pun">();</span><span class="pln"> </span><span class="com">// function User { ... }</span></pre>

<p>
	يمكن استخدام ذلك بداخل الدالة لمعرفة إن استُدعِيَت مع <code>new</code>، "في وضع بناء كائن"، أو بدونه "في الوضع العادي".
</p>

<p>
	يمكننا أيضًا جعل كلًا من الاستدعاء العادي و <code>new</code> ينفِّذان الأمر ذاته -بناء كائن- هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_17" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">User</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">new</span><span class="pun">.</span><span class="pln">target</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// new إن كنت تعمل بدون </span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// new ...سأضيف </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">

let john </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="str">"John"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// new User تُوَجِّه الاستدعاء إلى </span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">john</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// John</span></pre>

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

<p>
	ربما ليس من الجيد استخدام ذلك في كل مكان، لأن حذف <code>new</code> يجعل ما يحدث أقل وضوحًا. لكن مع <code>new</code>، يعلم الجميع أن كائنًا جديدًا قد أُنشِئ.
</p>

<h2>
	ما تُرجِعه الدوال البانية
</h2>

<p>
	لا تملك الدوال البانية عادةً التعليمة <code>return</code>. فَمُهِمَتُهَا هي كتابة الأمور المهمة إلى <code>this</code>، وتصبح تلقائيًا هي النتيجة. لكن إن كان هناك التعليمة <code>return</code> فإن القاعدة بسيطة:
</p>

<ul>
<li>
		إن استُدعِيَت <code>return</code> مع كائن، يُرجَع الكائن بدلًا من <code>this</code>.
	</li>
	<li>
		إن استُدعِيَت <code>return</code> مع متغير أولي، يُتَجاهَل.
	</li>
</ul>
<p>
	بمعنىً آخر، <code>return</code> مع كائن يُرجَع الكائن، وفي الحالات الأخرى تُرجَع <code>this</code>. مثلًا، يعاد في المثال التالي الكائن المرفق بعد <code>return</code> ويهمل الكائن المسنَد إلى <code>this</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_19" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">BigUser</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"> </span><span class="str">"John"</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"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Godzilla"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">  </span><span class="com">// &lt;-- تُرجِع هذا الكائن</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">BigUser</span><span class="pun">().</span><span class="pln">name </span><span class="pun">);</span><span class="pln">  </span><span class="com">// Godzilla, حصلنا على الكائن</span></pre>

<p>
	وهنا مثال على استعمال <code>return</code> فارغة (أو يمكننا وضع متغير أولي بعدها، لا فرق):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_21" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">SmallUser</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"> </span><span class="str">"John"</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">return</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ← this تُرجِع </span><span class="pln">
</span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">SmallUser</span><span class="pun">().</span><span class="pln">name </span><span class="pun">);</span><span class="pln">  </span><span class="com">// John</span></pre>

<p>
	لا تحوي الدوال البانية غالبًا على تعليمة الإعادة <code>return</code>. نذكر هنا هذا التصرف الخاص عند إرجاع الكائنات بغرض شمول جميع النواحي.
</p>

<h3>
	<strong>حذف الاقواس</strong>
</h3>

<p>
	بالمناسبة، يمكننا حذف أقواس <code>new</code> في حال غياب المعاملات مُعامِلات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_23" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">User</span><span class="pun">;</span><span class="pln"> </span><span class="com">// &lt;-- لا يوجد أقوس</span><span class="pln">
</span><span class="com">// الغرض ذاته</span><span class="pln">
let user </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">User</span><span class="pun">();</span></pre>

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

<h2>
	الدوال في الباني
</h2>

<p>
	استخدام الدوال البانية لإنشاء الكائنات يُعطي مرونة كبيرة. قد تحوي الدالة البانية على مُعامِلات ترشد في بناء الكائن ووضعه، إذ يمكننا إضافة خاصيات ودوال إلى <code>this</code> بالطبع. مثلًا، تُنشِئ <code>new User(name)‎</code> في الأسفل كائنًا بالاسم المُعطَى <code>name</code> والدالة <code>sayHi</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_25" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">User</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">sayHi </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">
    alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"My name is: "</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="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let john </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="str">"John"</span><span class="pun">);</span><span class="pln">

john</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// My name is: John</span><span class="pln">

</span><span class="com">/*
john = {
   name: "John",
   sayHi: function() { ... }
}
*/</span></pre>

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

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

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

<p>
	تزود JavaScript دوالًا بانية للعديد من الأنواع (الكائنات) المدمجة في اللغة: مثل النوع <code>Date</code> للتواريخ، و <code>Set</code> للمجموعات وغيرها من الكائنات التي نخطط لدراستها.
</p>

<h3>
	<strong>عودة قريبة</strong>
</h3>

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

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

<h2>
	تمارين
</h2>

<h3>
	دالتين - كائن واحد
</h3>

<p class="task__importance">
	الأهمية: 2
</p>

<p>
	هل يمكن إنشاء الدالة <code>A</code> و <code>B</code> هكذا <code>new A()==new B()‎</code>؟
</p>

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

let a </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> A</span><span class="pun">;</span><span class="pln">
let b </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> B</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> a </span><span class="pun">==</span><span class="pln"> b </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	إن كان ممكنًا، وضح ذلك بمثال برمجي.
</p>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<p>
		نعم يمكن ذلك.
	</p>

	<p>
		إن كان هناك دالة تُرجِع كائنًا فإن <code>new</code> تُرجِعه بدلًا من <code>this</code>. لذا فمن الممكن، مثلًا، إرجاع الكائن المعرف خارجيًا <code>obj</code>:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_29" style="">
<span class="pln">let obj </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"> A</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><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">return</span><span class="pln"> obj</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">new</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">new</span><span class="pln"> B</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>
</div>

<h2>
	إنشاء حاسبة جديدة
</h2>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	إنشِئ دالة بانية باسم <code>Calculator</code> تنشئ كائنًا بثلاث دوال:
</p>

<ul>
<li>
		<code>read()‎</code> تطلب قيمتين باستخدام سطر الأوامر وتحفظها في خاصيات الكائن.
	</li>
	<li>
		<code>sum()‎</code> تُرجِع مجموع الخاصيتين.
	</li>
	<li>
		<code>mul()‎</code> تُرجِع حاصل ضرب الخاصيتين.
	</li>
</ul>
<p>
	مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_31" style="">
<span class="pln">let calculator </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Calculator</span><span class="pun">();</span><span class="pln">
calculator</span><span class="pun">.</span><span class="pln">read</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Sum="</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> calculator</span><span class="pun">.</span><span class="pln">sum</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Mul="</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> calculator</span><span class="pun">.</span><span class="pln">mul</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_33" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Calculator</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">read </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">a </span><span class="pun">=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">prompt</span><span class="pun">(</span><span class="str">'a?'</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">this</span><span class="pun">.</span><span class="pln">b </span><span class="pun">=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">prompt</span><span class="pun">(</span><span class="str">'b?'</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">this</span><span class="pun">.</span><span class="pln">sum </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">a </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</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">this</span><span class="pun">.</span><span class="pln">mul </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">a </span><span class="pun">*</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">b</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let calculator </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Calculator</span><span class="pun">();</span><span class="pln">
calculator</span><span class="pun">.</span><span class="pln">read</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Sum="</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> calculator</span><span class="pun">.</span><span class="pln">sum</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Mul="</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> calculator</span><span class="pun">.</span><span class="pln">mul</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span></pre>
</div>

<h2>
	إنشاء مجمِّع
</h2>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	انشِئ دالة بانية باسم <code>Accumulator(startingValue)‎</code>، إذ يجب أن يتصف هذا الكائن بأنَّه:
</p>

<ul>
<li>
		يخزن القيمة الحالية في الخاصية <code>value</code>. تُعَيَّن قيمة البدء عبر المعامل <code>startingValue</code> المعطى من الدالة البانية.
	</li>
	<li>
		يجب أن تستخدم الدالة <code>read()</code> الدالة <code>prompt</code> لقراءة رقم جديد وإضافته إلى <code>value</code>.
	</li>
</ul>
<p>
	بمعنى آخر، الخاصية <code>value</code> هي مجموع القيم المدخلة بواسطة المستخدم بالإضافة إلى القيمة الأولية <code>startingValue</code>.
</p>

<p>
	هنا مثال على ما يجب أن يُنَفَّذ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_35" style="">
<span class="pln">let accumulator </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Accumulator</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln"> </span><span class="com">// القيمة الأولية 1</span><span class="pln">

accumulator</span><span class="pun">.</span><span class="pln">read</span><span class="pun">();</span><span class="pln"> </span><span class="com">// يضيف قيمة مدخلة بواسطة المستخدم</span><span class="pln">
accumulator</span><span class="pun">.</span><span class="pln">read</span><span class="pun">();</span><span class="pln"> </span><span class="com">// يضيف قيمة مدخلة بواسطة المستخدم</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">accumulator</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln"> </span><span class="com">// يعرض مجموع القيم</span></pre>

<p>
	<strong>الحل</strong>
</p>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8005_37" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Accumulator</span><span class="pun">(</span><span class="pln">startingValue</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> startingValue</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">read </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">value </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">prompt</span><span class="pun">(</span><span class="str">'How much to add?'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

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

let accumulator </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Accumulator</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
accumulator</span><span class="pun">.</span><span class="pln">read</span><span class="pun">();</span><span class="pln">
accumulator</span><span class="pun">.</span><span class="pln">read</span><span class="pun">();</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">accumulator</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span></pre>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/constructor-new" rel="external nofollow">Constructor, operator "new"</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript Language</a>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}
code {
    background-color: rgb(250, 250, 250);
    border-radius: 3px;
}</style>
<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%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-r815/" rel="">توابع الأنواع الأولية</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%AD%D9%88%D9%8A%D9%84-%D9%85%D9%86-%D9%86%D9%88%D8%B9-%D9%83%D8%A7%D8%A6%D9%86-%D8%A5%D9%84%D9%89-%D9%86%D9%88%D8%B9-%D8%A3%D9%88%D9%84%D9%8A-r800/" rel="">التحويل من نوع كائن إلى نوع أولي</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">801</guid><pubDate>Thu, 20 Feb 2020 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x62D;&#x648;&#x64A;&#x644; &#x645;&#x646; &#x646;&#x648;&#x639; &#x643;&#x627;&#x626;&#x646; &#x625;&#x644;&#x649; &#x646;&#x648;&#x639; &#x623;&#x648;&#x644;&#x64A; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%AD%D9%88%D9%8A%D9%84-%D9%85%D9%86-%D9%86%D9%88%D8%B9-%D9%83%D8%A7%D8%A6%D9%86-%D8%A5%D9%84%D9%89-%D9%86%D9%88%D8%B9-%D8%A3%D9%88%D9%84%D9%8A-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r800/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_01/30.jpg.80a58d9109949858e9f834fc93fe4991.jpg" /></p>

<p>
	ماذا يحدث عند جمع كائنين بالشكل <code>obj1 + obj2</code>، أو طرح كائنين <code>obj1 - obj2</code> أو طباعة الكائنات باستخدام <code>alert(obj)‎</code>؟ تحوَّل الكائنات في مثل هذه الحالات إلى أنواع أولية (primitives) ثم تُنَفَّذ العملية.
</p>

<p>
	رأينا في فصل <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%AD%D9%88%D9%8A%D9%84-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%A3%D9%86%D9%88%D8%A7%D8%B9-r673/" rel="">تحويل الأنواع</a> قواعد التحويل بين الأنواع الأساسية مثل الارقام، النصوص أو القيم المنطقية، لكن بقيت فجوة متعلقة بالكائنات. الآن بعد أن تعرفنا على الرموز والدوال، يمكن ملء هذه الفجوة.
</p>

<p>
	1- في السياق المنطقي (boolean)، جميع الكائنات تساوي القيمة <code>true</code>، إذ يوجد تحوَّل الكائنات إلى أرقام ونصوص فقط.
</p>

<p>
	2- يحدث التحويل العددي (numeric) عند طرح الكائنات أو تنفيذ العمليات الرياضية عليها. مثلًا، يمكن طرح كائنات <code>Date</code> (سيتم شرحها في فصل التاريخ والوقت) ويكون ناتج طرح <code>date1 - date2</code> هو الفارق الزمني بين التاريخين.
</p>

<p>
	3- بالنسبة للتحويل إلى نص (string)، يحدث ذلك عادةً عند إخراج كائن بالطريقة <code>alert(obj)‎</code> وأي سياق مشابه.
</p>

<h2>
	التحويل إلى أنواع أساسية عبر <code>ToPrimitive</code>
</h2>

<p>
	يمكننا ضبط التحويل إلى نص أو عدد باستخدام دوال خاصة بالكائنات. يوجد ثلاثة أنواع للتحويل بين الأنواع (يطلق عليها «النوع المخمَّن» [hint] الذي سيجري تحويل الكائن إليه)، مشروحة في <a href="https://tc39.github.io/ecma262/#sec-toprimitiv" rel="external nofollow">هذه المواصفات</a>:
</p>

<h3>
	إلى سلسلة نصية <code>"string"</code>
</h3>

<p>
	يُجرَى التحويل من كائن لنص عند القيام بعمليات على كائن تتوقع أن يكون الكائن نصًا، مثل <code>alert</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1602_7" style="">
<span class="com">// المخرجات</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">);</span><span class="pln">

</span><span class="com">// استخدام كائن كمفتاح للخاصية</span><span class="pln">
anotherObj</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="lit">123</span><span class="pun">;</span></pre>

<h3>
	إلى عدد <code>"number"</code>
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6595_6" style="">
<span class="com">// تحويل صريح</span><span class="pln">
let num </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">);</span><span class="pln">

</span><span class="com">// ( عمليات رياضية (عدى عملية الجمع الأحادي</span><span class="pln">
let n </span><span class="pun">=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">obj</span><span class="pun">;</span><span class="pln"> </span><span class="com">// عملية جمع أحادية</span><span class="pln">
let delta </span><span class="pun">=</span><span class="pln"> date1 </span><span class="pun">-</span><span class="pln"> date2</span><span class="pun">;</span><span class="pln">

</span><span class="com">// عملية موازنة أصغر/أكبر</span><span class="pln">
let greater </span><span class="pun">=</span><span class="pln"> user1 </span><span class="pun">&gt;</span><span class="pln"> user2</span><span class="pun">;</span></pre>

<h3>
	إلى نوع افتراضي <code>"default"</code>
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1602_11" style="">
<span class="com">// الجمع الثنائي</span><span class="pln">
let total </span><span class="pun">=</span><span class="pln"> car1 </span><span class="pun">+</span><span class="pln"> car2</span><span class="pun">;</span><span class="pln">

</span><span class="com">// obj == string/number/symbol</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">};</span></pre>

<p>
	يمكن لِمعاملات الموازنة أكبر/أصغر <code>&lt;&gt;</code> التعامل أيضًا مع كلً من النصوص والأعداد لكنها ترجح التحويل إلى عدد دون النظر إلى التحويل الافتراضي المرجح في هذه الحالة وذلك لأسباب تاريخية.
</p>

<p>
	عمليًا، تُطبِّق جميع الكائنات المُدمجة في اللغة التحويل الافتراضي <code>"default"</code> بنفس طريقة التحويل إلى عدد <code>"number"</code>. وربما يجب أن نقوم بذلك أيضًا. (عدا الكائن <code>Date</code>، والذي سَنتعلمه لاحقَا.)
</p>

<p>
	لاحظ أن هناك ثلاثة أنواع للتحويل فقط، إذ الأمر بهذه البساطة. لا يوجد تحويل للنوع المنطقي (boolean، فجميع الكائنات تحمل القيمة <code>true</code> في السياق المنطقي) أو أي شيء آخر. وإن عاملنا كلًا من التحويل الافتراضي <code>"default"</code> والتحويل العددي <code>"number"</code> بالطريقة ذاتها كما تقوم أغلب الدوال المدمجة، فسيكون هنالك تحويلين فقط.
</p>

<p>
	<strong>تحاول JavaScript العثور على ثلاث دوال للكائن واستدعائها عند القيام بالتحويل</strong>
</p>

<ol>
<li>
		استدعاء <code>obj[Symbol.toPrimitive](hint)‎</code> - الدالة ذات المفتاح الرمزي <code>Symbol.toPrimitive</code> (رمز نظام)، إن كانت هذه الدالة موجودة.
	</li>
	<li>
		أو إن كان النوع المخمَّن هو نص <code>"string"</code>
		<ul>
<li>
				جرب <code>obj.toString()‎</code> و <code>obj.valueOf()‎</code>، أيًا كانت متواجدة.
			</li>
		</ul>
</li>
	<li>
		إن كان hint هو عدد <code>"number"</code> أو <code>"default"</code>
		<ul>
<li>
				جرب <code>obj.valueOf()‎</code> و <code>obj.toString()‎</code> أيًا كانت متواجدة.
			</li>
		</ul>
</li>
</ol>
<h3>
	تابع التحويل <code>Symbol.toPrimitive</code>
</h3>

<p>
	لنبدأ من التابع الأول؛ يوجد رمز مُضَمَّن في JavaScript مُسَمَّى <code>Symbol.toPrimitive</code> والذي يجب استخدامه لتسمية تابع التحويل، هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1602_13" style="">
<span class="pln">obj</span><span class="pun">[</span><span class="typ">Symbol</span><span class="pun">.</span><span class="pln">toPrimitive</span><span class="pun">]</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">hint</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// يجب أن تُرجِع قيمة أولية</span><span class="pln">
  </span><span class="com">// النوع المخمَّن هو إما نص أو عدد أو النوع الافتراضي</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	مثلا، الكائن <code>user</code> هنا يتضمنها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1602_15" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  money</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="typ">Symbol</span><span class="pun">.</span><span class="pln">toPrimitive</span><span class="pun">](</span><span class="pln">hint</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(`</span><span class="pln">hint</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">hint</span><span class="pun">}`);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> hint </span><span class="pun">==</span><span class="pln"> </span><span class="str">"string"</span><span class="pln"> </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">"${this.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">money</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// تجربة للتحويل:</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">);</span><span class="pln"> </span><span class="com">// hint: string -&gt; {name: "John"}</span><span class="pln">
alert</span><span class="pun">(+</span><span class="pln">user</span><span class="pun">);</span><span class="pln"> </span><span class="com">// hint: number -&gt; 1000</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">user </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">// hint: default -&gt; 1500</span></pre>

<p>
	كما يمكننا أن نرى في الشيفرة، أصبح <code>user</code> نصًا يصف نفسه أو كمية من المال وفقًا للتحويل. تقوم الدالة <code>user[Symbol.toPrimitive]‎</code> بجميع حالات التحويل.
</p>

<h3>
	التحويل إلى نص عبر <code>toString</code> أو <code>valueOf</code>
</h3>

<p>
	ظهر التابعان <code>toString</code> و <code>valueOf</code> منذ وقت طويل، ولا يتبعان إلى نوع الرمز (symbol، إذ لم تكن الرموز موجودة في ذلك الحين)، لكنهما تابعين مسميان بأسماء توحي بارتباطهما بالنوع النصي، إذ كانت توفر آلية لعملية التحويل أصبحت قديمة النمط الآن.
</p>

<p>
	إن لم يكن هناك تنفيذًا للتابع <code>Symbol.toPrimitive</code> فتحاول JavaScript إيجاد هذه الدوال بالترتيب التالي:
</p>

<ul>
<li>
		<code>toString -&gt;‏ valueOf</code> للنصوص.
	</li>
	<li>
		<code>valueOf -&gt;‏ toString</code> لباقي الأنواع.
	</li>
</ul>
<p>
	مثلا، يقوم الكائن <code>user</code> بنفس الغرض السابق باستخدام <code>toString</code> و <code>valueOf</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1602_17" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  money</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">// في حال النوع المخمَّن سلسلة نصية</span><span class="pln">
  toString</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">name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"${this.name}"</span><span class="pun">}`;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  </span><span class="com">// في حال النوع المخمَّن عدد أو النوع الافتراضي</span><span class="pln">
  valueOf</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">money</span><span class="pun">;</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="pln">user</span><span class="pun">);</span><span class="pln"> </span><span class="com">// toString -&gt; {name: "John"}</span><span class="pln">
alert</span><span class="pun">(+</span><span class="pln">user</span><span class="pun">);</span><span class="pln"> </span><span class="com">// valueOf -&gt; 1000</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">user </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">// valueOf -&gt; 1500</span></pre>

<p>
	كما رأينا، يتنفذ السلوك ذاته كما في المثال السابق الذي استخدم <code>Symbol.toPrimitive</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1602_19" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">

  toString</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">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">

alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">);</span><span class="pln"> </span><span class="com">// toString -&gt; John</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">user </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">// toString -&gt; John500</span></pre>

<p>
	سينفِّذ التابع <code>toString</code> بجميع التحويلات الأولية في غياب كلًا من <code>Symbol.toPrimitive</code> و <code>valueOf</code>.
</p>

<h2>
	الأنواع المعادة
</h2>

<p>
	الأمر المهم الذي يجب معرفته عن جميع دوال التحويل بين الأنواع الأولية هو أنها لا تُرجِع بالضرورة النوع المخمَّن (hint) الأولي ذاته. لا يوجد تحكم في ما إن كانت <code>toString()‎</code> ترجع نصًا، أو أن <code>Symbol.toPrimitive</code> تُرجِع عددًا عند تحويل عدد. الأمر الوحيد المعروف والثابت هو أنَّ هذه الدوال تُرجِع نوعًا اوليًا وليس كائنًا.
</p>

<p>
	<strong>ملاحظة تاريخية</strong>
</p>

<p>
	لا يوجد خطأ إن أعاد التابع <code>toString</code> أو <code>valueOf</code> كائنًا، وذلك لأسباب تاريخية، لكن يتم تجاهل مثل هذه القيم (وكأن الدالة ليست موجودة). وذلك لعدم وجود مبدأ الخطأ الجيد (good error) في JavaScript حينها.
</p>

<p>
	بالمقابل، يجب أن يعيد التابع <code>Symbol.toPrimitive</code> قيمة أولية، وإلا فسيكون هناك خطأ.
</p>

<h2>
	عمليات تحويل إضافية
</h2>

<p>
	عرفنا مسبقًا أن جميع العوامل (operator) والدوال تجري عمليات تحويل على الأنواع التي تتعامل معها مثل معامل الضرب <code>*</code> يحول جميع المُعامَلات (operands) إلى أعداد. فإن مرَّرنا كائنًا عبر وسيط إلى إحدى الدوال أو العمليات، فستمر عملية التحويل على مرحلة أو مرحلتين هما:
</p>

<ol>
<li>
		يحوَّل الكائن إلى نوع أولي (باستعمال القواعد التي تحدثنا عنها آنفًا)
	</li>
	<li>
		إن لم يكن النوع الأولي الناتج مطابقًا للنوع المطلوب، فيحوَّل إلى النوع المطلوب وفق مبدأ التحويل بين الأنواع الأولية
	</li>
</ol>
<p>
	إليك المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6595_12" style="">
<span class="pln">let obj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// جميع التحويلات في غياب باقي الدوال toString  يجري التابع </span><span class="pln">
  toString</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"2"</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// حُوِّل الكائن إلى القيمةا لأولية "2", ثم جعلته عملية الضرب عددًا</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">obj </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 4 </span></pre>

<ol>
<li>
		حوَّلت عملية الضرب <code>obj * 2</code> الكائن إلى نوع أولي، وكان النوع المعاد من عملية التحويل سلسلةً نصية، هي <code>"2"</code>.
	</li>
	<li>
		جرى بعدئذٍ تحويل تلك السلسلة في العملية <code>‎"2" * 2</code>، إلى عدد ليصبح <code>2 * 2</code>.
	</li>
</ol>
<p>
	في المثال التالي، يقوم الجمع الثنائي بدمج النصوص في هذه الحالة والاكتفاء بعملية تحويل الكائن إلى سلسلة نصية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6595_14" style="">
<span class="pln">let obj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  toString</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"2"</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// (أعادت عملية التحويل إلى نوع أولي نصًا =&gt; دمج)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">obj </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 22 </span></pre>

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

<p>
	تجرَى عملية التحويل من كائن لنوع أولي تلقائيًا بواسطة العديد من الدوال المدمجة في اللغة والمُعاملات التي تتوقع أن تتعامل مع قيم أولية.
</p>

<p>
	يخمَّن النوع الأولي المراد تحويل الكائن إليه إلى:
</p>

<ul>
<li>
		سلسلة نصية <code>"string"</code> (للدالة <code>alert</code> والعمليات الأخرى التي تتعامل مع نصوص)
	</li>
	<li>
		عدد <code>"number"</code> (للعمليات الرياضية) -النوع الافتراضي <code>"default"</code> (لبعض العوامل)
	</li>
</ul>
<p>
	تُحدِّد المواصفات النوع المخمَّن (hint) الذي يستخدمه كل مُعامل بوضوح. يوجد القليل من العوامل التي لا تعلم ما النوع المتوقع وتستخدم النوع الافتراضي <code>"default"</code>. يُعامل النوع الافتراضي <code>"default"</code> معامل العدد <code>"number"</code> في الكائنات أغلب الأحيان؛ لذا، يتم دمج النوعين عمليًا.
</p>

<p>
	خوارزمية التحويل كالتالي:
</p>

<ol>
<li>
		استدعاء <code>obj[Symbol.toPrimitive](hint)‎</code> إن وُجِدَت،
	</li>
	<li>
		أو إن كان النوع المخمَّن هو نص <code>"string"</code>
		<ul>
<li>
				جرب <code>obj.toString()‎</code> و <code>obj.valueOf()‎</code>، أيًا كانت متواجدة.
			</li>
		</ul>
</li>
	<li>
		إن كان النوع المُخمَّن هو عدد <code>"number"</code> أو <code>"default"</code>
		<ul>
<li>
				جرب <code>obj.valueOf()‎</code> و <code>obj.toString()‎</code> أيًا كانت متواجدة.
			</li>
		</ul>
</li>
</ol>
<p>
	عمليًا، يكفي استخدام <code>obj.toString()‎</code> فقط لإجراء جميع التحويلات، إذ تعيد "شيئًا مقروءًا" يمثِّل الكائن يستعمل هذا التمثيل لعملية التسجيل أو التنقيح.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/object-toprimitive" rel="external nofollow">Object to primitive conversion</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript Language</a>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}
code {
    background-color: rgb(250, 250, 250);
    border-radius: 3px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D8%A7%D9%86%D9%8A-%D9%88%D8%A7%D9%84%D8%B9%D8%A7%D9%85%D9%84-new-r801/" rel="">الباني والعامل "new"</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%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84%D9%87%D8%A7-this-r799/" rel="">الدوال في الكائنات واستعمالها this</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">800</guid><pubDate>Tue, 18 Feb 2020 13:02:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; &#x641;&#x64A; &#x627;&#x644;&#x643;&#x627;&#x626;&#x646;&#x627;&#x62A; &#x648;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644;&#x647;&#x627; this &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84%D9%87%D8%A7-this-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r799/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_01/29.jpg.83f07ac50b20445f5c61dbb9fe6c2f15.jpg" /></p>

<p>
	تُنشّأ الكائنات عادة لتُمَثِّل أشياء من العالم الحقيقي مثل المستخدمين، والطلبات، وغيرها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_7" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	يمكن للمستخدم في العالم الحقيقي أن يقوم بعدة تصرفات: مثل اختيار شيء من سلة التسوق، تسجيل الدخول، والخروج …إلخ. تُمَثَّل هذه التصرفات في لغة JavaScript بإسناد دالة إلى خاصية وتدعى الدالة آنذاك بالتابع (method، أي دالة تابعة لكائن).
</p>

<h2>
	أمثلة على الدوال
</h2>

<p>
	بدايةً، لنجعل المستخدم <code>user</code> يقول مرحبًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_9" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

user</span><span class="pun">.</span><span class="pln">sayHi </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">
  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">

user</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Hello!</span></pre>

<p>
	استخدمنا هنا تعبير الدالة لإنشاء دالة تابع للكائن <code>user</code> وربطناها بالخاصية <code>user.sayHi</code> ثم استدعينا الدالة. هكذا أصبح بإمكان المستخدم التحدث! الآن أصبح لدى الكائن <code>user</code> الدالة <code>sayHi</code>.
</p>

<p>
	يمكننا أيضًا استخدام دالة معرفة مسبقًا بدلًا من ذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_11" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// أولا، نعرف دالة</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> sayHi</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">

</span><span class="com">// أضِف الدالة للخاصية لإنشاء تابع</span><span class="pln">
user</span><span class="pun">.</span><span class="pln">sayHi </span><span class="pun">=</span><span class="pln"> sayHi</span><span class="pun">;</span><span class="pln">

user</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Hello!</span></pre>

<p>
	<strong>البرمجة الشيئية (Object-oriented programming)</strong>
</p>

<p>
	يسمى كتابة الشيفرة البرمجية باستخدام الكائنات للتعبير عن الاشياء «بالبرمجة الشيئية/كائنية» (<a href="https://en.wikipedia.org/wiki/Object-oriented_programming" rel="external nofollow">object-oriented programming</a>، تُختَصَر إلى "<abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr>"). <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr> هو موضوع كبيرجدًا، فهو علم مشوق ومستقل بذاته. يعلمك كيف تختار الكائنات الصحيحة؟ كيف تنظم التفاعل فيما بينها؟ كما يعد علمًا للهيكلة ويوجد العديد من الكتب الأجنبية الجيدة عن هذا الموضوع مثل كتاب “Design Patterns: Elements of Reusable Object-Oriented Software” للمؤلفين E.Gamma، و R.Helm، و R.Johnson، و J.Vissides أو كتاب “Object-Oriented Analysis and Design with Applications” للمؤلف G.Booch، وغيرهما.
</p>

<h3>
	اختصار الدالة
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_13" style="">
<span class="com">// يتصرف الكائنان التاليان بالطريقة نفسها</span><span class="pln">

user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sayHi</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">
    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">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// يبدو شكل الدالة المختصر أفضل، أليس كذلك؟</span><span class="pln">
user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// مثل "sayHi: function()"</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">
</span><span class="pun">};</span></pre>

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

<h2>
	الكلمة المفتاحية "this" في الدوال
</h2>

<p>
	من المتعارف أن الدوال تحتاج للوصول إلى المعلومات المخزنة في الكائن لِتنفذ عملها. مثلًا، قد تحتاج الشيفرة التي بداخل <code>user.sayHi()‎</code> لِاسم المستخدم <code>user</code>. هنا، <strong>يمكن للدالة استخدام الكلمة المفتاحية <code>this</code> للوصول إلى نسخة الكائن التي استدعتها</strong>. أي، قيمة <code>this</code> هي الكائن "قبل النقطة" الذي استُخدِم لاستدعاء الدالة. مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_15" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">

  sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// هو الكائن الحالي "this" </span><span class="pln">
    alert</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">

user</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// John</span></pre>

<p>
	أثناء تنفيذ <code>user.sayHi()‎</code> هنا، ستكون قيمة <code>this</code> هي الكائن <code>user</code>.
</p>

<p>
	عمليًا، يمكن الوصول إلى الكائن بدون استخدام <code>this</code> بالرجوع إليه باستخدام اسم المتغير الخارجي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_17" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">

  sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "user" يدلًا من "this"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_19" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">

  sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">name </span><span class="pun">);</span><span class="pln"> </span><span class="com">// يتسبب في خطأ</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

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


let admin </span><span class="pun">=</span><span class="pln"> user</span><span class="pun">;</span><span class="pln">
user </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"> </span><span class="com">// تغيير المحتوى لتوضيح الأمر</span><span class="pln">

admin</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// يُرجِع خطأ sayHi() استخدام الاسم القديم بِداخل </span></pre>

<p>
	إن استخدمنا <code>this.name</code> بدلًا من <code>user.name</code> بداخل <code>alert</code>، فستعمل الشيفرة عملًا صحيحًا.
</p>

<h2>
	"this" غير محدودة النطاق
</h2>

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

<pre class="ipsCode prettyprint lang-lua prettyprinted" id="ips_uid_2571_21" style="">
<span class="kwd">function</span><span class="pln"> sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">this</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>this</code> أثناء تنفيذ الشيفرة بالاعتماد على السياق. مثلًا، في المثال التالي، تم تعيين الدالة ذاتها إلى كائنين مختلفين فيصبح لكل منهما قيمة مختلفة لـ "this" أثناء الاستدعاء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_23" style="">
<span class="pln">let user </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">"John"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
let admin </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">"Admin"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="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="com">// استخدام الدالة ذاتها مع كائنين مختلفين</span><span class="pln">
user</span><span class="pun">.</span><span class="pln">f </span><span class="pun">=</span><span class="pln"> sayHi</span><span class="pun">;</span><span class="pln">
admin</span><span class="pun">.</span><span class="pln">f </span><span class="pun">=</span><span class="pln"> sayHi</span><span class="pun">;</span><span class="pln">

</span><span class="com">// this لدى الاستدعائين قيمة مختلفة لـ</span><span class="pln">
</span><span class="com">// التي بداخل الدالة تعني المتغير الذي قبل النقطة "this"</span><span class="pln">
user</span><span class="pun">.</span><span class="pln">f</span><span class="pun">();</span><span class="pln"> </span><span class="com">// John  (this == user)</span><span class="pln">
admin</span><span class="pun">.</span><span class="pln">f</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Admin  (this == admin)</span><span class="pln">

admin</span><span class="pun">[</span><span class="str">'f'</span><span class="pun">]();</span><span class="pln"> </span><span class="com">// Admin (يمكن الوصول إلى الدالة عبر الصيغة النقطية أو الأقواس المربعة – لا يوجد مشكلة في ذلك)</span></pre>

<p>
	القاعدة ببساطة: إذا استُدعِيَت الدالة <code>obj.f()‎</code>، فإن <code>this</code> هي <code>obj</code> أثناء استدعاء <code>f</code>؛ أي إما <code>user</code> أو <code>admin</code> في المثال السابق.
</p>

<p>
	<strong>استدعاءٌ دون كائن: <code>this == undefined</code></strong>
</p>

<p>
	يمكننا استدعاء الدالة دون كائن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_25" style="">
<span class="kwd">function</span><span class="pln"> sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</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">

sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// undefined - غير معرَّف</span></pre>

<p>
	في هذه الحالة ستكون قيمة <code>this</code> هي <code>undefined</code> في الوضع الصارم. فإن حاولنا الوصول إلى <code>this.name</code> سيكون هناك خطأ.
</p>

<p>
	في الوضع غير الصارم، فإن قيمة <code>this</code> في هذه الحالة ستكون المتغير العام (في المتصفح <code>window</code> والتي سَنشرحها في فصل المتغيرات العامة). هذا السلوك زمني يستخدم إصلاحات الوضع الصارم <code>"use strict"</code>.
</p>

<p>
	يُعد هذا الاستدعاء خطأً برمجيًا غالبًا. فإن وًجِدت <code>this</code> بداخل دالة، فمن المتوقع استدعاؤها من خلال كائن.
</p>

<p>
	<strong>الأمور المترتبة على <code>this</code> الغير محدودة النطاق</strong>
</p>

<p>
	إن أتيت من لغة برمجية أخرى، فمن المتوقع أنك معتاد على "<code>this</code> المحدودة" إذ يمكن لِلدوال المعرَّفة في الكائن استخدام <code>this</code> التي ترجع للكائن.
</p>

<p>
	تستخدم <code>this</code> بحرية في JavaScript، وتُقَيَّم قيمتها أثناء التنفيذ ولا تعتمد على المكان حيث عُرِّفت فيه، بل على الكائن الذي قبل النقطة التي استدعت الدالة.
</p>

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

<h2>
	ميزة داخلية: النوع المرجعي
</h2>

<p>
	يُغطي هذا الجزء ميزة متقدمة -من ميزات اللغة-لفهم أفضل لحالة معينة. إن كنت على عجلة من أمرك، يمكنك تخطي أو تأجيل هذا الجزء.
</p>

<p>
	يمكن لاستدعاء الدالة المعقد أن يفقد <code>this</code>، فمثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_27" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  hi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</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">
  bye</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">"Bye"</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

user</span><span class="pun">.</span><span class="pln">hi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// John (يعمل الاستدعاء البسيط)</span><span class="pln">

</span><span class="com">// user.hi أو وفقًا للاسم user.bye الآن، لنستدعي </span><span class="pln">
</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="str">"John"</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">hi </span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">bye</span><span class="pun">)();</span><span class="pln"> </span><span class="com">// خطأ!</span></pre>

<p>
	يوجد معامل شرطي في السطر الأخير والذي يختار إما <code>user.hi</code> أو <code>user.bye</code>. في هذه الحالة يتم اختيار <code>user.hi</code> ثم يتم استدعاء الدالة مع الأقواس <code>()</code>. لكنها لا تعمل!
</p>

<p>
	كما ترى، ينتج خطأ من الاستدعاء لأن قيمة <code>"this"</code> بداخل الاستدعاء أصبحت <code>undefined</code>.
</p>

<p>
	ستعمل بهذه الطريقة (الكائن.الدالة):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_29" style="">
<span class="pln">user</span><span class="pun">.</span><span class="pln">hi</span><span class="pun">();</span></pre>

<p>
	هذه الصياغة لا تُعطي دالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_31" style="">
<span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="str">"John"</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">hi </span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">bye</span><span class="pun">)();</span><span class="pln"> </span><span class="com">// خطأ!</span></pre>

<p>
	لماذا؟ إن أردنا فهم سبب حدوث ذلك، لِنكشف الغطاء عن كيفية عمل الاستدعاء <code>obj.method()‎</code>. عند النظر عن قرب، يمكننا ملاحظة عمليتين في التعليمة <code>obj.method()‎</code>:
</p>

<p>
	1- أولا، النقطة <code>'.'</code> تسترجع الخاصية <code>obj.method</code>. 2- ثم الأقواس <code>()</code> تنفذ الدالة.
</p>

<p>
	إذًا، كيف تُمرَّر المعلومات عن <code>this</code> من الجزء الأول للثاني؟ إن وضعنا العمليتين في سطرين منفصلين، فَسنفقد <code>this</code> بالتأكيد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_33" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  hi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</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="com">// فصل الحصول على الدالة واستدعائها في سطرين منفصلين</span><span class="pln">
let hi </span><span class="pun">=</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">hi</span><span class="pun">;</span><span class="pln">
hi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// غير مُعَرَّفَة this خطأ، لأن</span></pre>

<p>
	تُسنِد التعليمة <code>hi = user.hi</code> الدالة إلى المتغير، ثم، في السطر الأخير تصبح مستقلة، فلا يوجد <code>this</code> هنا ضمن النطاق.
</p>

<p>
	<strong>تستخدم JavaScript خدعة لجعل <code>user.hi()‎</code> تعمل - صيغة النقطة <code>'.'</code> لا تُرجِع دالة، بل قيمة من <a href="https://tc39.github.io/ecma262/#sec-reference-specification-type" rel="external nofollow">النوع المرجعي</a> الخاص</strong>
</p>

<p>
	النوع المرجعي هو "نوع للتخصيص". لا يمكننا استخدام هذا النوع بشكل واضح، بل يُسخدَم داخليًا بواسطة اللغة. تُشَكَّل قيمة النوع المرجعي من ثلاث قيم <code>(base, name, strict)</code>، إذ:
</p>

<ul>
<li>
		<code>base</code> هي الكائن.
	</li>
	<li>
		<code>name</code> هو اسم الخاصية.
	</li>
	<li>
		<code>strict</code> تساوي "true" إن كان الوضع الصارم <code>use strict</code> مُفعلًا.
	</li>
</ul>
<p>
	النتيجة من الوصول إلى خاصية <code>user.hi</code> ليست دالة، إنما قيمة من النوع المرجعي. بالنسبة لـ <code>user.hi</code> في الوضع الصارم تكون:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_35" style="">
<span class="com">// قيمة من النوع المرجعي</span><span class="pln">
</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="str">"hi"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span></pre>

<p>
	عند استدعاء الأقواس <code>()</code> في النوع المرجعي فإنها تستقبل المعلومة كاملة عن الكائن والدلة، وتتمكن من تعيين <code>this</code> بطريقة صحيحة (في هذه الحالة <code>user</code>).
</p>

<p>
	النوع المرجعي هو نوع "وسيط" داخلي، وغرضه هو تمرير المعلومات من الصيغة النُقطية <code>.</code> إلى أقواس الاستدعاء <code>()</code>.
</p>

<p>
	أي عملية أخرى مثل الإسناد <code>hi = user.hi</code> تُلغي النوع المرجعي ككل، فهي تأخذ قيمة الدالة <code>user.hi</code> وتُمررها. فَتفقد العمليات التالية <code>this</code>. لذا، ونتيجة لذلك، تُمرَّر قيمة <code>this</code> بالطريقة الصحيحة إن كانت الدالة مُستدعاه مباشرة باستخدام صيغة النقطة <code>obj.method()‎</code> أو الأقواس المربعة <code>obj['method']()‎</code> (يؤديان العمل ذاته). سنتعلم طرائق أخرى لحل هذه المشكلة لاحقًا، مثل استخدام <a href="https://javascript.info/bind#solution-2-bind" rel="external nofollow">func.bind()</a>.
</p>

<h2>
	الدوال السهمية لا تحوي "this"
</h2>

<p>
	الدوال السهمية (Arrow function) هي دوال خاصة: فهي لا تملك <code>this</code> مخصصة لها. إن وضعنا <code>this</code> في إحدى هذه الدوال فَستؤخذ قيمة <code>this</code> من الدالة الخارجية.
</p>

<p>
	مثلًا، تحصل الدالة <code>arrow()‎</code> على قيمة <code>this</code> من الدالة الخارجية <code>user.sayHi()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_37" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  firstName</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Ilya"</span><span class="pun">,</span><span class="pln">
  sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let arrow </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"> alert</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">firstName</span><span class="pun">);</span><span class="pln">
    arrow</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

user</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Ilya</span></pre>

<p>
	يُعد ذلك إحدى ميزات دوال الدوال السهمية، وهي مفيدة عندما لا نريد استخدام <code>this</code> مستقلة، ونريد أخذها من السياق الخارجي بدلًا من ذلك. سَنتعمق في موضوع الدوال السهمية لاحقًا في مقال «<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AD%D8%AF%D9%8A%D8%AB-%D8%B9%D9%86-%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-%D9%85%D8%B1%D8%A9-%D8%A3%D8%AE%D8%B1%D9%89-r880/" rel="">نظرة تفصيلية على الدوال السهمية Arrow functions</a>».
</p>

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

<ul>
<li>
		الدوال المخزنة في الكائنات تسمى «توابع» (methods).
	</li>
	<li>
		تسمح هذه الكائنات باستدعائها بالشكل <code>object.doSomething()‎</code>.
	</li>
	<li>
		يمكن للدوال الوصول إلى الكائن المعرفة فيه (أو النسخة التي استدعته المشتقة منه) باستخدام الكلمة المفتاحية<code>this</code>.
	</li>
	<li>
		تُعَرَّف قيمة <code>this</code> أثناء التنفيذ.
	</li>
	<li>
		قد نستخدم <code>this</code> عند تعريف دالة، لكنها لا تملك أي قيمة حتى استدعاء الدالة.
	</li>
	<li>
		يمكن نسخ دالة بين الكائنات.
	</li>
	<li>
		عند استدعاء دالة بالصيغة <code>object.method()‎</code>، فإن قيمة <code>this</code> أثناء الاستدعاء هي <code>object</code>.
	</li>
</ul>
<p>
	لاحظ أن الدوال السهمية مختلفة تتعامل تعاملًا مختلفًا مع <code>this</code> إذ لا تملك قيمة لها. عند الوصول إلى <code>this</code> بداخل دالة سهمية فإن قيمتها تؤخذ من النطاق الموجودة فيه.
</p>

<h2>
	تمارين
</h2>

<h3>
	فحص الصياغة
</h3>

<p class="task__importance">
	الأهمية: 2
</p>

<p>
	ما نتيجة هذه الشيفرة؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_39" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  go</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"> alert</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="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)()</span></pre>

<p>
	ملاحظة: يوجد فخ <img alt=":)" data-emoticon="true" height="20" src="https://academy.hsoub.com/uploads/monthly_2015_02/smile.png.cf72ab87c1aaefd42371e0a7de39cfae.png" srcset="https://academy.hsoub.com/uploads/emoticons/smile@2x.png 2x" title=":)" width="20"></p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		خطأ! جرب تشغيل الشيفرة:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_41" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  go</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"> alert</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="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)()</span><span class="pln"> </span><span class="com">// خطأ!</span></pre>

	<p>
		لا تعطي مُعظم رسائل الخطأ في المتصفحات توضيح لسبب الخطأ.
	</p>

	<p>
		<strong>سبب الخطأ هو فاصلة منقوطة مفقودة بعد <code>user = {...}‎</code></strong>.
	</p>

	<p>
		لا تقوم JavaScript بوضع فاصلة منقوطة قبل القوس <code>‎(user.go)()‎</code>. لذا فإنها تقرأ الشيفرة كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_47" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> go</span><span class="pun">:...</span><span class="pln"> </span><span class="pun">}(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)()</span></pre>

	<p>
		يمكننا أيضًا رؤية أن هذا التعبير المتداخل هو استدعاء للكائن <code>{ go: ...‎ }</code> كدالة بالمعامل <code>(user.go)</code>. ويحدث ذلك أيضًا في السطر نفسه مع <code>let user</code>، لذا فإن الكائن <code>user</code> لم يُعَرَّف بعد، وهكذا يظهر الخطأ.
	</p>

	<p>
		إن وضعنا الفاصلة المنقوطة، سيصبح كل شيء صحيح:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_49" style="">
<span class="pln">let user </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">"John"</span><span class="pun">,</span><span class="pln">
  go</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"> alert</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="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)()</span><span class="pln"> </span><span class="com">// John</span></pre>

	<p>
		لاحظ أن الأقواس حول <code>(user.go)</code> لا تعمل شيئًا هنا. فهي ترتب العمليات غالبًا، لكن النقطة لها الأولوية على أي حال. لذا فليس هناك أي تأثير. فقط الفاصلة المنقوطة هي الخطأ.
	</p>
</div>

<h3>
	شرح قيمة "this"
</h3>

<p class="task__importance">
	الأهمية: 3
</p>

<p>
	استدعينا الدالة <code>user.go()‎</code> في الشيفرة التي بالأسفل 4 مرات متتالية. لكن الاستدعاءان <code>(1)</code> و <code>(2)</code> يعملان عملًا مختلفًا عن الاستدعائين <code>(3)</code> و <code>(4)</code>. لماذا؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_51" style="">
<span class="pln">let obj</span><span class="pun">,</span><span class="pln"> method</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">
  go</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"> alert</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">

obj</span><span class="pun">.</span><span class="pln">go</span><span class="pun">();</span><span class="pln">               </span><span class="com">// (1) [object Object]</span><span class="pln">

</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)();</span><span class="pln">             </span><span class="com">// (2) [object Object]</span><span class="pln">

</span><span class="pun">(</span><span class="pln">method </span><span class="pun">=</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)();</span><span class="pln">    </span><span class="com">// (3) غير معرف</span><span class="pln">

</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">go </span><span class="pun">||</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">stop</span><span class="pun">)();</span><span class="pln"> </span><span class="com">// (4) غير معرف</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		هنا التوضيح:
	</p>

	<p>
		1- يُعد استدعاء دالة عادي.
	</p>

	<p>
		2- مثل 1 تمامًا، لا تغير الأقواس ترتيب العمليات هنا، تعمل النقطة أولًا على أي حال.
	</p>

	<p>
		3- هنا لدينا استدعاء أكثر تعقيدًا <code>‎(expression).method()‎</code>. يعمل الاستدعاء كما لو تم فصله إلى سطرين:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_53" style="">
<span class="pln">f </span><span class="pun">=</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">go</span><span class="pun">;</span><span class="pln"> </span><span class="com">// حساب التعبير</span><span class="pln">
f</span><span class="pun">();</span><span class="pln">        </span><span class="com">// الاستدعاء</span></pre>

	<p>
		تُنَفَّذ <code>f()‎</code> هنا كدالة، دون <code>this</code>.
	</p>

	<p>
		4- مشابة ل <code>(3)</code>، لدينا تعبيرًا يسار النقطة <code>.</code>.
	</p>

	<p>
		لشرح سلوك الاستدعائين <code>(3)</code> و <code>(4)</code>، نحتاج لإعادة استدعاء معاملات الوصول لتلك الخاصية (النقطة أو الأقواس المربعة) التي ترجع قيمة من النوع المرجعي.
	</p>

	<p>
		أي عملية عليها عدا استدعاء الدالة (مثل التعيين <code>=</code> أو <code>||</code>) تُرجِعُها إلى قيمة عادية، والتي لا تحمل المعلومات التي تسمح بتعيين <code>this</code>.
	</p>
</div>

<h3>
	استخدام <code>this</code> في الكائن معرَّف باختصار عبر الأقواس
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	تُرجِع الدالة <code>makeUser</code> كائنًا هنا. ما النتيجة من الدخول إلى <code>ref</code> الخاص بها؟ ولماذا؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_55" style="">
<span class="kwd">function</span><span class="pln"> makeUser</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">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">,</span><span class="pln">
    ref</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let user </span><span class="pun">=</span><span class="pln"> makeUser</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">ref</span><span class="pun">.</span><span class="pln">name </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ما النتيجة؟</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		الإجابة: ظهور خطأ. جربها:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_57" style="">
<span class="kwd">function</span><span class="pln"> makeUser</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">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">,</span><span class="pln">
    ref</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let user </span><span class="pun">=</span><span class="pln"> makeUser</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">ref</span><span class="pun">.</span><span class="pln">name </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ِلِقيمة غير معرفة 'name' خطأ: لا يمكن قراءة الخاصية </span></pre>

	<p>
		ذلك لأن القواعد التي تعين <code>this</code> لا تنظر إلى تعريف الكائن. ما يهم هو وقت الاستدعاء. قيمة <code>this</code> هنا بداخل <code>makeUser()‎</code> هي <code>undefined</code>، لأنها استُدعيَت كدالة منفصلة، وليس كدالة بصياغة النقطة.
	</p>

	<p>
		قيمة <code>this</code> هي واحدة للدالة ككل، ولا تؤثر عليها أجزاء الشيفرة ولا حتى الكائنات. لذا فإن <code>ref: this</code> تأخذ <code>this</code> الحالي للدالة.
	</p>

	<p>
		هنا حالة معاكسة تمامًا:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_59" style="">
<span class="kwd">function</span><span class="pln"> makeUser</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">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">,</span><span class="pln">
    ref</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">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let user </span><span class="pun">=</span><span class="pln"> makeUser</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">ref</span><span class="pun">().</span><span class="pln">name </span><span class="pun">);</span><span class="pln"> </span><span class="com">// John</span></pre>

	<p>
		أصبحت تعمل هنا لأن <code>user.ref()‎</code> هي دالة، وقيمة <code>this</code> تعَيَّن للكائن الذي قبل النقطة <code>'.'</code>.
	</p>
</div>

<h3>
	إنشاء آلة حاسِبة
</h3>

<p class="task__importance">
	الأهمية: 5
</p>

<p>
	أنشئ كائنًا باسم <code>calculator</code> يحوي الدوال الثلاث التالية:
</p>

<ul>
<li>
		<code>read()‎</code> تطلب قيمتين وتحفظها كخصائص الكائن.
	</li>
	<li>
		<code>sum()‎</code> تُرجِع مجموع القيم المحفوظة.
	</li>
	<li>
		<code>mul()‎</code> تضرب القيم المحفوظة وتُرجِع النتيجة.
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_61" style="">
<span class="pln">let calculator </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">

calculator</span><span class="pun">.</span><span class="pln">read</span><span class="pun">();</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> calculator</span><span class="pun">.</span><span class="pln">sum</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> calculator</span><span class="pun">.</span><span class="pln">mul</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span></pre>

<h4>
	الحل
</h4>

<div class="task__answer">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_63" style="">
<span class="pln">let calculator </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sum</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">a </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">b</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  mul</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">a </span><span class="pun">*</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">b</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  read</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">a </span><span class="pun">=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">prompt</span><span class="pun">(</span><span class="str">'a?'</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">this</span><span class="pun">.</span><span class="pln">b </span><span class="pun">=</span><span class="pln"> </span><span class="pun">+</span><span class="pln">prompt</span><span class="pun">(</span><span class="str">'b?'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

calculator</span><span class="pun">.</span><span class="pln">read</span><span class="pun">();</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> calculator</span><span class="pun">.</span><span class="pln">sum</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> calculator</span><span class="pun">.</span><span class="pln">mul</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span></pre>
</div>

<h3>
	التسلسل
</h3>

<p class="task__importance">
	الأهمية: 2
</p>

<p>
	لدينا الكائن <code>ladder</code> (سُلَّم) الذي يتيح الصعود والنزول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_65" style="">
<span class="pln">let ladder </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  step</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  up</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">step</span><span class="pun">++;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  down</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">step</span><span class="pun">--;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  showStep</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// يعرض الخطوة الحالية</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">step </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_2571_67" style="">
<span class="pln">ladder</span><span class="pun">.</span><span class="pln">up</span><span class="pun">();</span><span class="pln">
ladder</span><span class="pun">.</span><span class="pln">up</span><span class="pun">();</span><span class="pln">
ladder</span><span class="pun">.</span><span class="pln">down</span><span class="pun">();</span><span class="pln">
ladder</span><span class="pun">.</span><span class="pln">showStep</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 1</span></pre>

<p>
	عَدِّل الشيفرة الخاصة بالدوال <code>up</code>، و <code>down</code>، و <code>showStep</code> لجعل الاستدعاءات متسلسلة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_69" style="">
<span class="pln">ladder</span><span class="pun">.</span><span class="pln">up</span><span class="pun">().</span><span class="pln">up</span><span class="pun">().</span><span class="pln">down</span><span class="pun">().</span><span class="pln">showStep</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 1</span></pre>

<p>
	يُستخدم هذا النمط بنطاق واسع في مكتبات JavaScript.
</p>

<h4>
	الحل
</h4>

<div class="task__answer">
	<p>
		الحل هو إرجاع الكائن نفسه من كل استدعاء.
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_71" style="">
<span class="pln">let ladder </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  step</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  up</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">step</span><span class="pun">++;</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  down</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">step</span><span class="pun">--;</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  showStep</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">step </span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

ladder</span><span class="pun">.</span><span class="pln">up</span><span class="pun">().</span><span class="pln">up</span><span class="pun">().</span><span class="pln">down</span><span class="pun">().</span><span class="pln">up</span><span class="pun">().</span><span class="pln">down</span><span class="pun">().</span><span class="pln">showStep</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 1</span></pre>

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

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2571_73" style="">
<span class="pln">ladder
  </span><span class="pun">.</span><span class="pln">up</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">up</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">down</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">up</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">down</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">showStep</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 1</span></pre>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/object-methods" rel="external nofollow">Object methods, "this"</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript Language</a>
</p>
<style type="text/css">
.task__importance {
    color: #999;
    margin-left: 30px;
}

.task__answer {
    border: 3px solid #f7f6ea;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}
code {
    background-color: rgb(250, 250, 250);
    border-radius: 3px;
}</style>
<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%AD%D9%88%D9%8A%D9%84-%D9%85%D9%86-%D9%86%D9%88%D8%B9-%D9%83%D8%A7%D8%A6%D9%86-%D8%A5%D9%84%D9%89-%D9%86%D9%88%D8%B9-%D8%A3%D9%88%D9%84%D9%8A-r800/" rel="">التحويل من نوع كائن إلى نوع أولي</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%86%D9%88%D8%B9-%D8%A7%D9%84%D8%B1%D9%85%D8%B2%D9%8A-symbol-r798/" rel="">النوع الرمزي (Symbol)</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">799</guid><pubDate>Sun, 16 Feb 2020 13:00:00 +0000</pubDate></item></channel></rss>
