<?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/10/?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;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x623;&#x62E;&#x637;&#x627;&#x621;&#x60C; &#x62C;&#x631;&#x628;... &#x627;&#x644;&#x62A;&#x642;&#x637; try..catch &#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%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1%D8%8C-%D8%AC%D8%B1%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%B7-trycatch-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r908/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_06/68.jpg.6336658a1d68fb0f82c23565c22533f9.jpg" /></p>
<p>
	مهما كنّا عباقرة نحن معشر المبرمجين، فلا بدّ أن تكون في السكربتات مشكلة ما. تحدث هذه المشاكل إمّا بسببنا، أو بسبب شيء أدخله المستخدم لم نتوقّعه، أو بسبب ردّ فيه خطأ من الخادوم، أو بمليار سبب آخر.
</p>

<p>
	في العادة ”يموت“ السكربت (أي يتوقّف مباشرة) لو حدث خطأ، ويطبع ذلك في الطرفية، لكن في كل الأحوال يمكن التعامل مع هذا الخطأ بعدة طرق.
</p>

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

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

<p>
	تتيح لنا الصياغة <code>try..catch</code> إمكانية ”التقاط“ هذه الأخطاء والقيام بما هو مفيد بدل أن يموت السكربت.
</p>

<h2>
	صياغة <code>try..catch</code>
</h2>

<p>
	للتعبير <code>try..catch</code> كتلتين برمجيتين أساسيتين: التجربة <code>try</code> والالتقاط <code>catch</code> بعدها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_7" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// الشيفرة...</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// التعامل مع الأخطاء</span><span class="pln">

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

<p>
	يعمل التعبير هكذا:
</p>

<ol>
	<li>
		أولًا، يجري تنفيذ الشيفرة في <code>try {...}‎</code>.
	</li>
	<li>
		لم نجح التنفيذ دون أيّ أخطاء، تُهمل الكتلة <code>catch(err)‎</code> وتصل عملية التنفيذ إلى نهاية <code>try</code> وتواصل عملها بعد تجاهل <code>catch</code>.
	</li>
	<li>
		إن حدث أيّ خطأ يتوقّف التنفيذ داخل كتلة <code>try</code> وينتقل سير العملية إلى بداية الكتلة <code>catch(err)‎</code>. سيحتوي المتغير <code>err</code> (يمكننا استبداله بأيّ اسم آخر) كائن خطأ فيه تفاصيل عمّا حدث.
	</li>
</ol>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="45674" href="https://academy.hsoub.com/uploads/monthly_2020_06/try-catch-flow.png.a6696074f3e425b4f3d42bac162a6d42.png" rel=""><img alt="try-catch-flow.png" class="ipsImage ipsImage_thumbnailed" data-fileid="45674" data-unique="f4nay6ylx" src="https://academy.hsoub.com/uploads/monthly_2020_06/try-catch-flow.thumb.png.fed3a865934d79857eed9e8dc6e73160.png"></a>
</p>

<p>
	بهذا لا تقتل الأخطاء داخل كتلة <code>try {…}‎</code> السكربت، فما زال ممكنًا أن نتعامل معها في <code>catch</code>.
</p>

<p>
	وقت الأمثلة.
</p>

<ul>
	<li>
		<p>
			إليك مثالًا ليس فيه أخطاء: يعرض <code>alert</code> السطرين <code>(1)</code> و <code>(2)</code>:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_9" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  alert</span><span class="pun">(</span><span class="str">'Start of try runs'</span><span class="pun">);</span><span class="pln">  </span><span class="com">// (1) &lt;-- بداية التشغيلات</span><span class="pln">

  </span><span class="com">// ...ما من أخطاء هنا</span><span class="pln">

  alert</span><span class="pun">(</span><span class="str">'End of try runs'</span><span class="pun">);</span><span class="pln">   </span><span class="com">// (2) &lt;-- نهاية التشغيلات</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="com">// (3)‫  تُهمل catch إذ ليست هناك أخطاء</span><span class="pln">
  alert</span><span class="pun">(</span><span class="str">'Catch is ignored, because there are no errors'</span><span class="pun">);</span><span class="pln">

</span><span class="pun">}</span></pre>
	</li>
	<li>
		<p>
			مثال فيه خطأ: يعرض السطرين <code>(1)</code> و<code>(3)</code>:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_11" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  alert</span><span class="pun">(</span><span class="str">'Start of try runs'</span><span class="pun">);</span><span class="pln">  </span><span class="com">// (1) &lt;-- بداية التشغيلات</span><span class="pln">

  lalala</span><span class="pun">;</span><span class="pln"> </span><span class="com">// error, variable is not defined! خطأ: المتغير غير معرّف!</span><span class="pln">

  alert</span><span class="pun">(</span><span class="str">'End of try (never reached)'</span><span class="pun">);</span><span class="pln">  </span><span class="com">// (2)‫ نهاية كتلة try (لا نصل إليها أبدًا)</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  alert</span><span class="pun">(`</span><span class="typ">Error</span><span class="pln"> has occurred</span><span class="pun">!`);</span><span class="pln"> </span><span class="com">// (3) &lt;-- حدث خطأ!</span><span class="pln">

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

<p>
	<strong>تحذير: لا يعمل تعبير <code>try..catch</code> إلّا مع الأخطاء أثناء التشغيل</strong> يجب أن تكون الشيفرة البرمجية صياغتها صحيحة لكي تعمل <code>try..catch</code> بعبارة أخرى، يجب أن تكون الشيفرة البرمجية خالية من أخطاء الصياغة.
</p>

<p>
	لن تعمل في هذه الحالة لأن هنالك أقواسًا مفتوحة بدون غُلاقاتها.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_14" style=""><span class="kwd">try</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">catch</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="str">"لا يمكن للمحرك فهم هذه الشيفرة فهي غير صحيحة"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أولًا يقرأ محرك جافاسكربت الشيفرة البرمجية، ومن ثمّ يشغّلها. تدعى الأخطاء التي تحدث في مرحلة القراءة أخطاء التحليل (parse-time) ولا يمكن إصلاحها (من داخل الشيفرة البرمجية نفسها). وذلك لأن محرك لغة جافاسكربت لا يستطيع فهم الشيفرة البرمجية من الأساس. <strong>تحذير</strong>:تعمل الصياغة <code>try..catch</code> بشكل متزامن. إذا حدث خطأ ما في شيفرة برمجية مجدولة مثلما في <code>setTimeout</code> فلن تستطيع الصياغة <code>try..catch</code> أن تلتقطه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_16" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    noSuchVariable</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="lit">1000</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"won't work"</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وذلك لأن التابِع سيُنفذ لاحقًا، بينما يكون محرك جافاسكربت غادر باني <code>try..catch</code>.
</p>

<p>
	للتقاط خطأ بداخل تابِع مُجدوَل يجب أن تكون الصياغة <code>try..catch</code> في داخل هذا التابِع.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_18" style=""><span class="pln">setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
</span><span class="com">// صياغة ‫try..catch تُعالح الخطأ </span><span class="pln">
    noSuchVariable</span><span class="pun">;</span><span class="pln"> </span><span class="com">// try..catch handles the error!</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"error is caught here!"</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">1000</span><span class="pun">);</span></pre>

<h2>
	كائن الخطأ Error
</h2>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_20" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ‫ هذا ”كائن الخطأ“، ويمكننا استعمال أيّ اسم نريد بدل err</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لكائن الخطأ (في حالة الأخطاء المضمّنة في اللغة) خاصيتين اثنتين:
</p>

<ul>
	<li>
		<p>
			<code>name</code>: اسم الخطأ. فمثلًا لو كان المتغير غير معرّفًا فسيكون الاسم <code>"ReferenceError"</code>.
		</p>
	</li>
	<li>
		<p>
			<code>message</code>: الرسالة النصية بتفاصيل الخطأ.
		</p>
	</li>
</ul>

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

<ul>
	<li>
		<code>stack</code>: مَكدس الاستدعاء الحالي: سلسلة نصية فيها معلومات عن سلسلة الاستدعاءات المتداخلة التي تسبّبت بالخطأ. نستعمل الخاصية للتنقيح فقط.
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_22" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="pun">*!*</span><span class="pln">
  lalala</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="kwd">catch</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">err</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ReferenceError(خطأ في الإشارة)</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">err</span><span class="pun">.</span><span class="pln">message</span><span class="pun">);</span><span class="pln"> </span><span class="com">// المتغيّر ‫lalala غير معرف</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">err</span><span class="pun">.</span><span class="pln">stack</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫ReferenceError:(خطأ في الإشارة) المتغيّر ‫lalala غير معرّف في (...call stack)</span><span class="pln">

  </span><span class="com">//يمكننا أيضًا عرض الخطأ بالكامل</span><span class="pln">
  </span><span class="com">//تحول الخطأ إلى سلسلة نصية هكذا ‫:"name: message"</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">err</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫ReferenceError:(خطأ في الإشارة) المتغيّر ‫lalala غير معرّف</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	إسناد "catch" الاختياري
</h2>

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

<p>
	لو لم تريد تفاصيل الخطأ فيمكنك إزالتها من <code>catch</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_24" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// &lt;-- بدون المتغير (err)</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	استعمال "try..catch"
</h2>

<p>
	هيًا نرى معًا مثالًا واقعيًا عن <code>try..catch</code>:
</p>

<p>
	كما نعلم فجافاسكربت تدعم التابِع <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse" rel="external nofollow">JSON.parse(str)</a>‎ ليقرأ القيم المرمّزة بِـ JSON.
</p>

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

<p>
	نستلم البيانات ونستدعي <code>JSON.parse</code> هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_26" style=""><span class="pln">let json </span><span class="pun">=</span><span class="pln"> </span><span class="str">'{"name":"John", "age": 30}'</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 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">json</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"> user</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"> user</span><span class="pun">.</span><span class="pln">age </span><span class="pun">);</span><span class="pln">  </span><span class="com">// 30</span></pre>

<p>
	يمكنك أن ترى تفاصيل أكثر عن JSON في درس <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 methods, toJSON</a>.
</p>

<p>
	<strong>لو كانت سلسلة <code>json</code> معطوبة، فسيُولّد <code>JSON.parse</code> خطأً و”ويموت“ السكربت.</strong>
</p>

<p>
	هل نقبل بالأمر الواقع المرير؟ لا وألف لا!
</p>

<p>
	في هذا الحال لن يعرف الزائر ما يحدث لو حدث للبيانات أمر (ما لم يفتح طرفية المطوّرين). وعادةً ما لا يحب الناس ما ”يموت“ أمامهم دون أن يُعطيهم رسالة خطأ.
</p>

<p>
	فلنستعمل <code>try..catch</code> للتعامل مع هذه المعضلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_28" style=""><span class="pln">let json </span><span class="pun">=</span><span class="pln"> </span><span class="str">"{ bad json }"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  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">json</span><span class="pun">);</span><span class="pln"> </span><span class="com">// &lt;-- لو حدث خطأ...</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="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</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">"Our apologies, the data has errors, we'll try to request it one more time."</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"> e</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"> e</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>catch</code> لعرض رسالة لا أكثر، ولكن يمكن أن نستغلّها أفضل من هذا: مثل إرسال طلب إلى الشبكة، أو اقتراح عملية بديلة على الزائر أو إرسال معلومات الخطأ إلى … تسجيل، وغيرها… هذا كلّه أفضل من الموت والموت فقط.
</p>

<h2>
	رمي أخطائنا نحن
</h2>

<p>
	ماذا لو كان كائن <code>json</code> صحيح صياغيًا إلّا أنّ الخاصية المطلوبة <code>name</code> ليست فيه؟ هكذا مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_30" style=""><span class="pln">let json </span><span class="pun">=</span><span class="pln"> </span><span class="str">'{ "age": 30 }'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// البيانات ناقصة</span><span class="pln">

</span><span class="kwd">try</span><span class="pln"> </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">json</span><span class="pun">);</span><span class="pln"> </span><span class="com">// &lt;-- لا أخطاء</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="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"doesn't execute"</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// لا يتنفّذ السطر</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هنا سيعمل التابِع <code>JSON.parse</code> كما يجب، لكن عدم وجود الخاصية <code>name</code> هي المشكلة والخطأ في هذه الحالة.
</p>

<p>
	لتوحيد طريقة معالجة الأخطاء، سنستخدم مُعامل <code>throw</code>.
</p>

<h3>
	مُعامل "الرمي" <code>throw</code>
</h3>

<p>
	يُولّد لنا مُعامل الرمي <code>throw</code> خطأً.
</p>

<p>
	صياغته هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_32" style=""><span class="kwd">throw</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">error object</span><span class="pun">&gt;</span></pre>

<p>
	يمكننا تقنيًا استعمال ما نريد ليكون كائن خطأ، مثل الأنواع الأولية كالأعداد والسلاسل النصية. ولكن من الأفضل استعمال الكائنات ومن الأفضل أكثر أن تملك خاصيتي الاسم <code>name</code> والرسالة <code>message</code> (لتكون متوافقة إلى حدٍّ ما مع الأخطاء المضمّنة).
</p>

<p>
	في جافاسكربت مختلف البانيات المضمّنة للأخطاء القياسية: الخطأ <code>Error</code> والخطأ الصياغي <code>SyntaxError</code> والخطأ في الإشارة <code>ReferenceError</code> والخطأ في النوع <code>TypeError</code> وغيرها. يمكننا استعمال هذه البانيات أيضًا لإنشاء كائنات الخطأ.
</p>

<p>
	صياغتها هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_34" style=""><span class="pln">let error </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="pln">message</span><span class="pun">);</span><span class="pln">
</span><span class="com">// أو</span><span class="pln">
let error </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">SyntaxError</span><span class="pun">(</span><span class="pln">message</span><span class="pun">);</span><span class="pln">
let error </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ReferenceError</span><span class="pun">(</span><span class="pln">message</span><span class="pun">);</span><span class="pln">
</span><span class="com">// ...</span></pre>

<p>
	في الأخطاء المضمّنة في اللغة (ولا أعني الكائنات أيًا كانت، الأخطاء بعينها) تكون قيمة الخاصية <code>name</code> هي ذاتها اسم الباني، وتُؤخذ الرسالة <code>message</code> من الوسيط.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_36" style=""><span class="pln">let error </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">"Things happen o_O"</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">error</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">
alert</span><span class="pun">(</span><span class="pln">error</span><span class="pun">.</span><span class="pln">message</span><span class="pun">);</span><span class="pln"> </span><span class="com">// غرائب وعجائب ة_ه</span></pre>

<p>
	لنرى نوع الخطأ الذي يُولّده التابِع <code>JSON.parse</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_38" style=""><span class="kwd">try</span><span class="pln"> </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="str">"{ bad json o_O }"</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">catch</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// SyntaxError خطأ صياغي</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">message</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Unexpected token o in JSON at position 2</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما رأينا فهو خطأ صياغي <code>SyntaxError</code>.
</p>

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

<p>
	هيًا نرمِ الخطأ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_40" style=""><span class="pln">let json </span><span class="pun">=</span><span class="pln"> </span><span class="str">'{ "age": 30 }'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// البيانات ناقصة</span><span class="pln">

</span><span class="kwd">try</span><span class="pln"> </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">json</span><span class="pun">);</span><span class="pln"> </span><span class="com">// &lt;-- لا أخطاء</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">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">SyntaxError</span><span class="pun">(</span><span class="str">"Incomplete data: no 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">

  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="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"JSON Error: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">message </span><span class="pun">);</span><span class="pln"> </span><span class="com">// خطأ ‫JSON: البيانات ناقصة: ليس هنالك اسم</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُولّد مُعامل <code>throw</code> (في السطر <code>(*)</code>) خطأً صياغيًا <code>SyntaxError</code> له الرسالة الممرّرة <code>message</code>، تمامًا كما تُولّد جافاسكربت نفسها الخطأ. بهذا يتوقّف التنفيذ داخل <code>try</code> وينتقل سير العملية إلى <code>catch</code>.
</p>

<p>
	الآن صارت الكتلة <code>catch</code> هي المكان الذي نتعامل فيه مع الأخطاء فحسب، أكانت أخطاء <code>JSON.parse</code> أم أخطاء أخرى.
</p>

<h2>
	إعادة الرمي
</h2>

<p>
	يمكننا في المثال أعلاه استعمال <code>try..catch</code> للتعامل مع البيانات الخاطئة. ولكن هل يمكن أن يحدث <em>خطأ آخر غير متوقّع</em> في كتلة <code>try {...}‎</code>؟ مثلًا لو كان خطأ المبرمج (لم يعرّف المتغير) أو شيئًا آخر ليس أنّ ”البيانات خاطئة“؟
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_42" style=""><span class="pln">let json </span><span class="pun">=</span><span class="pln"> </span><span class="str">'{ "age": 30 }'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// البيانات ناقصة</span><span class="pln">

</span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  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">json</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫ نسينا ”let“ قبل user</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  alert</span><span class="pun">(</span><span class="str">"JSON Error: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> err</span><span class="pun">);</span><span class="pln">   </span><span class="com">// خطأ ‫JSON: خطأ في الإشارة: user غير معرّف (في الواقع، ليس خطأ JSON)</span><span class="pln">

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

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

<p>
	في حالتنا هذه على <code>try..catch</code> التقاط أخطاء ”البيانات الخاطئة“ فقط، ولكنّ طبيعة <code>catch</code> هي أن تلتقط <em>كلّ</em> الأخطاء من <code>try</code>. فهنا مثلًا التقطت خطأً غير متوقع ولكنها ما زالت تصرّ على رسالة <code>"JSON Error"</code>. هذا ليس صحيحًا ويصعّب من تنقيح الشيفرة كثيرًا.
</p>

<p>
	لحسن الحظ فيمكننا معرفة الخطأ الذي التقطناه، من اسمه <code>name</code> مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_44" style=""><span class="kwd">try</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="com">/*...*/</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">e</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></pre>

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

<p>
	<strong>على catch التعامل مع الأخطاء التي تعرفها فقط، و”إعادة رمي“ ما دونها.</strong>
</p>

<p>
	يمكننا توضيح فكرة ”إعادة الرمي“ بهذه الخطوات:
</p>

<ol>
	<li>
		تلتقط <code>catch</code> كلّ الأخطاء.
	</li>
	<li>
		نحلّل كائن الخطأ <code>err</code> في كتلة <code>catch(err) {...}‎</code>.
	</li>
	<li>
		لو لم نعرف طريقة التعامل معه، رميناه <code>throw err</code>.
	</li>
</ol>

<p>
	في الشيفرة أسفله استعملنا إعادة الرمي لتتعامل الكتلة <code>catch</code> مع أخطاء الصياغة فقط <code>SyntaxError</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_46" style=""><span class="pln">let json </span><span class="pun">=</span><span class="pln"> </span><span class="str">'{ "age": 30 }'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// البيانات ناقصة</span><span class="pln">
</span><span class="kwd">try</span><span class="pln"> </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">json</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">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">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">SyntaxError</span><span class="pun">(</span><span class="str">"Incomplete data: no 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">

  blabla</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">name </span><span class="pun">);</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="str">"SyntaxError"</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">"JSON Error: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">message </span><span class="pun">);</span><span class="pln"> </span><span class="com">// خطأ JSON: كذا كذا</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">throw</span><span class="pln"> e</span><span class="pun">;</span><span class="pln"> </span><span class="com">// نُعيد رميه (*)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

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

<p>
	الخطأ المرمي في السطر <code>(*)</code> داخل كتلة <code>catch</code> ”يسقط خارج أرض“ <code>try..catch</code> ويمكننا إمّا التقاطه باستعمال تعبير <code>try..catch</code> خارجي (لو كتبناه) أو سيقتل الخطأ السكربت.
</p>

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

<p>
	يوضّح المثال أسفله كيفية التقاط هذه الأخطاء بمستويات أخرى من <code>try..catch</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_48" style=""><span class="kwd">function</span><span class="pln"> readData</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let json </span><span class="pun">=</span><span class="pln"> </span><span class="str">'{ "age": 30 }'</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
    blabla</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">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</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">e</span><span class="pun">.</span><span class="pln">name </span><span class="pun">!=</span><span class="pln"> </span><span class="str">'SyntaxError'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">throw</span><span class="pln"> e</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="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  readData</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"External catch got: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> e </span><span class="pun">);</span><span class="pln"> </span><span class="com">// التقطناه أخيرًا!</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هكذا لا تعرف الدالة <code>readData</code> إلّا طريقة التعامل مع أخطاء الصياغة <code>SyntaxError</code>، بينما تتصرّف تعابير <code>try..catch</code> الخارجية بغيرها من أخطاء (إن عرفتها).
</p>

<h2>
	try..catch..finally
</h2>

<p>
	لحظة… لم ننتهي بعد.
</p>

<p>
	يمكن أيضًا أن يحتوي تعبير <code>try..catch</code> على مُنغلقة أخرى: <code>finally</code>.
</p>

<p>
	لو كتبناها فستعمل في كلّ الحالات الممكنة:
</p>

<ul>
	<li>
		بعد <code>try</code> لو لم تحدث أخطاء
	</li>
	<li>
		وبعد <code>catch</code> لو حدثت أخطاء.
	</li>
</ul>

<p>
	هكذا هي الصياغة ”الموسّعة“:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_50" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="pun">...</span><span class="pln"> </span><span class="pun">نحاول</span><span class="pln"> </span><span class="pun">تنفيذ</span><span class="pln"> </span><span class="pun">الشيفرة</span><span class="pln"> </span><span class="pun">...</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="pun">...</span><span class="pln"> </span><span class="pun">نتعامل</span><span class="pln"> </span><span class="pun">مع</span><span class="pln"> </span><span class="pun">الأخطاء</span><span class="pln"> </span><span class="pun">...</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> finally </span><span class="pun">{</span><span class="pln">
   </span><span class="pun">...</span><span class="pln"> </span><span class="pun">ننفّذه</span><span class="pln"> </span><span class="pun">مهما</span><span class="pln"> </span><span class="pun">كان</span><span class="pln"> </span><span class="pun">الحال</span><span class="pln"> </span><span class="pun">...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	جرّب تشغيل هذه الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_52" style=""><span class="kwd">try</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">'try'</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">confirm</span><span class="pun">(</span><span class="str">'Make an error?'</span><span class="pun">))</span><span class="pln"> BAD_CODE</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">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'catch'</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"> finally </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'finally'</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>

<ol>
	<li>
		لو كانت الإجابة على ”أتريد ارتكاب خطأ؟“ ”نعم“، فستعمل هكذا <code>try -&gt; catch -&gt; finally</code>.
	</li>
	<li>
		لو رفضت ذلك، فستعمل هكذا <code>try -&gt; finally</code>.
	</li>
</ol>

<p>
	نستعمل عادةً مُنغلقة <code>finally</code> متى ما شرعنا في شيء وأردنا إنهائه مهما كانت نتيجة الشيفرة.
</p>

<p>
	فمثلًا نريد قياس الوقت الذي تأخذه دالة أعداد فيبوناتشي <code>fib(n)‎</code>. الطبيعي أن نبدأ القياس قبل التشغيل ونُنهيه بعده، ولكن ماذا لو حدث خطأ أثناء استدعاء الدالة؟ مثلًا خُذ شيفرة الدالة <code>fib(n)‎</code> أسفله وسترى أنّها تُعيد خطأً لو كانت الأعداد سالبة أو لم تكن أعدادًا صحيحة (not integer).
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_54" 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 positive integer number?"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">35</span><span class="pun">)</span><span class="pln">

let diff</span><span class="pun">,</span><span class="pln"> result</span><span class="pun">;</span><span class="pln">

</span><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">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">trunc</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="pun">{</span><span class="pln">
    </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">"Must not be negative, and also an integer."</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">

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">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  result </span><span class="pun">=</span><span class="pln"> fib</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">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  result </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">*!*</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> finally </span><span class="pun">{</span><span class="pln">
  diff </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> start</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">result </span><span class="pun">||</span><span class="pln"> </span><span class="str">"error occurred"</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">execution took $</span><span class="pun">{</span><span class="pln">diff</span><span class="pun">}</span><span class="pln">ms</span><span class="pun">`</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	يمكنك التأكّد بتشغيل الشيفرة وإدخال <code>35</code> في <code>prompt</code>، وستعمل كما يجب، أي تكون <code>finally</code> بعد <code>try</code>. وبعد ذلك جرّب إدخال <code>‎-1</code> وسترى خطأً مباشرةً وسيأخذ تنفيذ الشيفرة مدّة <code>0ms</code>، وكِلا الزمنين المقيسين صحيحين.
</p>

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

<p>
	<strong>ملاحظة</strong>:المتغيّرات في صياغة <code>try..catch..finally</code> محلية. لاحظ أن المتغيرات <code>result</code> و <code>diff</code> في الشيفرة البرمجية أعلاه معرّفة قبل الصياغة <code>try..catch</code>.
</p>

<p>
	وبذلك إذا عرفنا <code>let</code> في الصياغة <code>try</code> فستبقى مرئية بداخلها فقط.
</p>

<p>
	<strong>ملاحظة</strong>: بخصوص <code>finally</code> و <code>return</code> فإن مُنغلقة <code>finally</code> تعمل مع أي خروج من صياغة <code>try..catch</code> والتي تتضمن خروج واضح من خلال تعليمة <code>return</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_56" style=""><span class="kwd">function</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">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="pun">*!*</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">*/!*</span><span class="pln">

  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">/* ... */</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> finally </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">'finally'</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"> func</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫أولًا ستعمل تعليمة alert من المنغلقة finally ومن ثمّ هذه</span></pre>

<p>
	<strong>ملاحظة</strong>: إن باني <code>try..finally</code> بدون منغلقة <code>catch</code> مفيد أيضًا إذ يمكننا استخدامه عندما لا نريد معالجة الأخطاء وإنما نريد التأكد من أن العمليات التي بدأناها انتهت فعلًا.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_58" style=""><span class="kwd">function</span><span class="pln"> func</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">try</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"> finally </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// نكمله هنا حتى وإن كلّ السكربت مات</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<h2>
	الالتقاط العمومي
</h2>

<p>
	<strong>تحذير</strong>: مخصص لبيئة العمل إن المعلومات في هذه الفقرة ليست جزءًا من لغة جافاسكربت
</p>

<p>
	لنقل مثلًا أنْ حصل خطأ فادح خارج تعبير <code>try..catch</code>، ومات السكربت (مثلًا كان خطأ المبرمج أو أيّ شيء آخر مريب).
</p>

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

<p>
	لا نجد في المواصفة أيّ شيء عن هذا، إلّا أنّ بيئات اللغة تقدّم هذه الميزة لأهميتها البالغة. فمثلًا تقدّم Node.js الحدث <a href="https://nodejs.org/api/process.html#process_event_uncaughtexception" rel="external nofollow"><code>process.on("uncaughtException")‎</code></a>. ولو كنّا نُطوّر للمتصفّح فيمكننا إسناد دالة إلى خاصية <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror" rel="external nofollow">window.onerror</a> الفريدة (إذ تعمل متى حدث خطأ لم يُلتقط).
</p>

<p>
	الصياغة هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_60" style=""><span class="pln">window</span><span class="pun">.</span><span class="pln">onerror </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">message</span><span class="pun">,</span><span class="pln"> url</span><span class="pun">,</span><span class="pln"> line</span><span class="pun">,</span><span class="pln"> col</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">};</span></pre>

<ul>
	<li>
		<p>
			<code>message</code>: رسالة الخطأ.
		</p>
	</li>
	<li>
		<p>
			<code>url</code>: عنوان URL للسكربت أين حدث الخطأ.
		</p>
	</li>
	<li>
		<p>
			<code>line</code> و<code>col</code>: رقم السطر والعمود أين حدث الخطأ.
		</p>
	</li>
	<li>
		<p>
			<code>error</code>: كائن الخطأ.
		</p>
	</li>
</ul>

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

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

  window</span><span class="pun">.</span><span class="pln">onerror </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">message</span><span class="pun">,</span><span class="pln"> url</span><span class="pun">,</span><span class="pln"> line</span><span class="pun">,</span><span class="pln"> col</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">message</span><span class="pun">}</span><span class="pln">\n </span><span class="typ">At</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">line</span><span class="pun">}:</span><span class="pln">$</span><span class="pun">{</span><span class="pln">col</span><span class="pun">}</span><span class="pln"> of $</span><span class="pun">{</span><span class="pln">url</span><span class="pun">}`);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">


  </span><span class="kwd">function</span><span class="pln"> readData</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    badFunc</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Whoops, something went wrong!</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

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

<p>
	عادةً، لا يكون الهدف من …. العمومي <code>window.onerror</code> استعادة تنفيذ السكربت (إذ هو أمر مستحيل لو كانت أخطاء من المبرمج) بل يكون لإرسال هذه الرسائل إلى المبرمج.
</p>

<p>
	كما أنّ هناك خدمات على الوِب تقدّم مزايا لتسجيل الأخطاء في مثل هذه الحالات، أمثال <a href="https://errorception.com" rel="external nofollow">https://errorception.com</a> و<a href="http://www.muscula.com" rel="external nofollow">http://www.muscula.com</a>.
</p>

<p>
	وهكذا تعمل:
</p>

<ol>
	<li>
		نُسجّل في الخدمة ونأخذ منهم شيفرة جافاسكربت صغيرة (أو عنوانًا للسكربت) لنضعها في صفحاتنا.
	</li>
	<li>
		يضبط هذا السكربت دالة <code>window.onerror</code> مخصّصة.
	</li>
	<li>
		ومتى حدث خطأ أرسلَ طلب شبكة بالخطأ إلى الخدمة.
	</li>
	<li>
		ويمكننا متى أردنا الولوج إلى واجهة الوِب للخدمة ومطالعة تلك الأخطاء.
	</li>
</ol>

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

<p>
	يتيح لنا تعبير <code>try..catch</code> التعامل مع الأخطاء أثناء تنفيذ الشيفرات. كما يدلّ اسمها فهي تسمح ”بتجربة“ تنفيذ الشيفرة و”والتقاط“ الأخطاء التي قد تحدث فيها.
</p>

<p>
	صياغتها هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_64" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// شغّل الشيفرة</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// انتقل إلى هنا لو حدث خطأ</span><span class="pln">
  </span><span class="com">// ‫err هو كائن الخطأ</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> finally </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// مهما كان الذي حدث، نفّذ هذا</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكننا إزالة قسم <code>catch</code> أو قسم <code>finally</code>، واستعمال الصيغ الأقصر <code>try..catch</code> و<code>try..finally</code>.
</p>

<p>
	لكائنات الأخطاء الخاصيات الآتية:
</p>

<ul>
	<li>
		<code>message</code>: رسالة الخطأ التي نفهمها نحن البشر.
	</li>
	<li>
		<code>name</code>: السلسلة النصية التي فيها اسم الخطأ (اسم باني الخطأ).
	</li>
	<li>
		<code>stack</code> (ليست قياسية ولكنّها مدعومة دعمًا ممتازًا): المَكدس في لحظة إنشاء الخطأ.
	</li>
</ul>

<p>
	لو لم تُرد كائن الخطأ فيمكنك إزالتها باستعمال <code>catch {</code> بدل <code>catch(err) {‎</code>.
</p>

<p>
	يمكننا أيضًا توليد الأخطاء التي نريد باستعمال مُعامل <code>throw</code>. تقنيًا يمكن أن يكون وسيط <code>throw</code> ما تريد ولكن من الأفضل لو كان كائن خطأ يرث صنف الأخطاء <code>Error</code> المضمّن في اللغة. سنعرف المزيد عن توسعة الأخطاء في القسم التالي.
</p>

<p>
	كما يُعدّ نمط ”إعادة الرمي“ البرمجي نمطًا مهمًا عند التعامل مع الأخطاء، فلا تتوقّع كتلة <code>catch</code> إلّا أنواع الأخطاء التي تفهمها وتعرف طريقة التعامل معها، والباقي عليها إعادة رميه لو لم تفهمه.
</p>

<p>
	حتّى لو لم نستعمل تعبير <code>try..catch</code> فأغلب البيئات تتيح لنا إعداد … أخطاء ”عمومي“ لالتقاط الأخطاء التي ”تسقط أرضًا“. هذا … في المتصفّحات اسمه <code>window.onerror</code>.
</p>

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

<h2>
	أخيرًا أم الشيفرة؟
</h2>

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

<p>
	وازِن بين الشيفرتين هتين.
</p>

<ol>
	<li>
		<p>
			تستعمل الأولى <code>finally</code> لتنفيذ الشيفرة بعد <code>try..catch</code>:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_66" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">عمل</span><span class="pln"> </span><span class="pun">عمل</span><span class="pln"> </span><span class="pun">عمل</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</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"> finally </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="pun">}</span></pre>

		<p>
			 
		</p>
	</li>
	<li>
		<p>
			الثانية تضع عملية التنظيف بعد <code>try..catch</code>:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_68" style=""><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">عمل</span><span class="pln"> </span><span class="pun">عمل</span><span class="pln"> </span><span class="pun">عمل</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">نتعامل</span><span class="pln"> </span><span class="pun">مع</span><span class="pln"> </span><span class="pun">الأخطاء</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">ننظّف</span><span class="pln"> </span><span class="pun">مكان</span><span class="pln"> </span><span class="pun">العمل</span><span class="pln"> </span><span class="com">// ‎هنا</span></pre>

		<p>
			سنحتاج بكل بتأكيد للتنظيف بعد العمل. بغض النظر إن وجدَنا خطأً ما أم لا.
		</p>
	</li>
</ol>

<p>
	هل هنالك ميزة إضافية لاستخدام <code>finally</code>؟ أم أن الشيفرتين السابقتين متساويتين؟ إن كان هنالك ميزّة اكتب مثلًا يوضحها.
</p>

<h4>
	الحل
</h4>

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

<p>
	يختلف السلوك إذا كان هناك "قفزة" من "try..catch".
</p>

<p>
	على سبيل المثال، عندما يكون هناك تعليمة <code>return</code> بداخل صياغة <code>try..catch</code>. تعمل منغلقة <code>finally</code> في حالة وجود أي خروج من صياغة <code>try..catch</code>، حتى عبر تعليمة <code>return</code>: مباشرة بعد الانتهاء من <code>try..catch</code> ، ولكن قبل أن تحصل شيفرة الاستدعاء على التحكم.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_70" 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">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">'start'</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"result"</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</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"> finally </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">'cleanup!'</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

f</span><span class="pun">();</span><span class="pln"> </span><span class="com">// cleanup!</span></pre>

<p>
	… أو عندما يكون هناك <code>throw</code>، مثل هنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3832_72" 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">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">'start'</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">"an error"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</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="pun">(</span><span class="str">"can't handle the error"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">throw</span><span class="pln"> e</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

  </span><span class="pun">}</span><span class="pln"> finally </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">'cleanup!'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

f</span><span class="pun">();</span><span class="pln"> </span><span class="com">// cleanup!</span></pre>

<p>
	تضمنُ <code>finally</code> عملية التنظيف هنا. إذا وضعنا الشيفرة البرمجية في نهاية <code>f</code> ، فلن تشغّل في هذا السيناريو.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/try-catch" rel="external nofollow">Error handling, "try..catch"‎</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>.
</p>
]]></description><guid isPermaLink="false">908</guid><pubDate>Thu, 02 Jul 2020 18:07:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x62E;&#x627;&#x644;&#x64A;&#x637; (Mixins) &#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%AE%D8%A7%D9%84%D9%8A%D8%B7-mixins-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r907/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_06/67.jpg.6beb7c72dd69a82fc358603832db4cab.jpg" /></p>
<p>
	لا يمكننا في جافاسكربت إلّا أن نرث كائنًا واحدًا فقط. وليس هناك إلّا كائن <code>[[Prototype]]</code> واحد لأيّ كائن. ولا يمكن للصنف توسعة أكثر من صنف واحد.
</p>

<p>
	وأحيانًا يكون ذلك مُقيّدًا نوعًا ما. فنقل بأنّ لدينا صنف ”كنّاسة شوارع“ <code>StreetSweeper</code> وصنف ”دراجة هوائية“ <code>Bicycle</code>، وأردنا صنع شيء يجمعهما: ”كنّاسة شوارع بدراجة هوائية“ <code>StreetSweepingBicycle</code>.
</p>

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

<p>
	هناك مفهوم في اللغة يساعد في حلّ هذه وهو ”المخاليط“ (Mixins).
</p>

<p>
	كما تقول ويكيبيديا، <a href="https://en.wikipedia.org/wiki/Mixin" rel="external nofollow">المخلوط</a> هو صنف يحتوي على توابِع يمكن للأصناف الأخرى استعمالها دون أن ترث ذاك الصنف.
</p>

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

<h2>
	مثال عن المخاليط
</h2>

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

<p>
	لنقل مثلًا لدينا المخلوط <code>sayHiMixin</code> ليُضيف بعض الكلام للمستخدم أو الصنف <code>User</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3490_8" style=""><span class="com">// مخلوط</span><span class="pln">
let sayHiMixin </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">
    alert</span><span class="pun">(`</span><span class="typ">Hello</span><span class="pln"> $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}`);</span><span class="pln"> </span><span class="com">// مرحبًا يا فلان</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  sayBye</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">Bye</span><span class="pln"> $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}`);</span><span class="pln"> </span><span class="com">// وداعًا يا فلان</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// الاستعمال:</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// ننسخ التوابِع</span><span class="pln">
</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">assign</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">,</span><span class="pln"> sayHiMixin</span><span class="pun">);</span><span class="pln">

</span><span class="com">// الآن يمكن أن يرحّب المستخدم بغيره</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">"Dude"</span><span class="pun">).</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Hello Dude! مرحبًا يا Dude!</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3490_10" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> extends </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">assign</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">,</span><span class="pln"> sayHiMixin</span><span class="pun">);</span></pre>

<p>
	يمكن أن تستفيد المخاليط من الوراثة بينها ذاتها المخاليط. فمثلًا، نرى هنا كيف يرث <code>sayHiMixin</code> المخلوطَ <code>sayMixin</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3490_12" style=""><span class="pln">let sayMixin </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  say</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">
    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">
</span><span class="pun">};</span><span class="pln">

let sayHiMixin </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> sayMixin</span><span class="pun">,</span><span class="pln"> </span><span class="com">// ‫(أو نستعمل Object.create لضبط كائن prototype هنا)</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">// نستدعي التابِع الأب</span><span class="pln">
    super</span><span class="pun">.</span><span class="pln">say</span><span class="pun">(`</span><span class="typ">Hello</span><span class="pln"> $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}`);</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  sayBye</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</span><span class="pun">.</span><span class="pln">say</span><span class="pun">(`</span><span class="typ">Bye</span><span class="pln"> $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}`);</span><span class="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="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// ننسخ التوابِع</span><span class="pln">
</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">assign</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">,</span><span class="pln"> sayHiMixin</span><span class="pun">);</span><span class="pln">

</span><span class="com">// الآن يمكن أن يرحّب المستخدم بالناس</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">"Dude"</span><span class="pun">).</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// مرحبًا يا ‫ Dude!</span></pre>

<p>
	لاحظ كيف يبحث استدعاء التابِع الأب <code>super.say()‎</code> في <code>sayHiMixin</code> (في الأسطر عند <code>(*)</code>) - كيف يبحث عن التابِع داخل كائن prototype المخلوطَ وليس داخل الصنف.
</p>

<p>
	إليك صورة (طالع الجانب الأيمن فيها):
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="45643" href="https://academy.hsoub.com/uploads/monthly_2020_06/mixin-inheritance.png.9a6162a886be301f90c994c02d4fc70d.png" rel=""><img alt="mixin-inheritance.png" class="ipsImage ipsImage_thumbnailed" data-fileid="45643" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_06/mixin-inheritance.thumb.png.3ec5262663b12732882e187750a7d66c.png"></a>
</p>

<p>
	يعزو ذلك إلى أنّ التابِعين <code>sayHi</code> و<code>sayBye</code> أُنشآ في البداية داخل <code>sayHiMixin</code>. فحتّى حين ننسخهما تُشير خاصية <code>[[HomeObject]]</code> الداخلية فيهما إلى <code>sayHiMixin</code> كما نرى في الصورة.
</p>

<p>
	وطالما يبحث <code>super</code> عن التوابِع الأب في <code>[[HomeObject]].[[Prototype]]</code> يكون البحث داخل <code>sayHiMixin.[[Prototype]]‎</code> وليس داخل <code>User.[[Prototype]]‎</code>.
</p>

<h2>
	مخلوط الأحداث EventMixin
</h2>

<p>
	الآن حان وقت استعمال المخاليط في الحياة العملية.
</p>

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

<ul>
	<li>
		سيقدّم المخلوط تابِعًا باسم ‎<code>.trigger(name, [...data])‎</code> ”يُولّد حدثًا“ متى حدث شيء مهم. وسيط الاسم <code>name</code> هو… اسم الحدث، وبعده تأتي بيانات الحدث إن احتجناها.
	</li>
	<li>
		كما والتابِع <code>.on(name, handler)‎</code> الذي سيُضيف دالة ”معاملة“ <code>handler</code> لتستمع إلى الأحداث حسب الاسم الذي مرّرناه. ستُستدعى الدالة متى تفعّل الحدث بالاسم <code>name</code> وسيُمرّر لها الوسطاء في استدعاء <code>.trigger</code>.
	</li>
	<li>
		وأيضًا… التابِع ‎<code>.off(name, handler)‎</code> الذي سيُزيل المستمع <code>handler</code>.
	</li>
</ul>

<p>
	بعدما نُضيف المخلوط سيقدر كائن المستخدم <code>user</code> على توليد حدث ولوج <code>"login"</code> متى ولج الزائر إلى الموقع. ويمكن لكائن آخر (لنقل التقويم <code>calendar</code>) الاستماع إلى هذا الحدث للقيام بمهمة ما (مثلًا تحميل تقويم المستخدم الذي ولج).
</p>

<p>
	أو يمكن أن تُولّد القائمة <code>menu</code> حدثَ الاختيار <code>"select"</code> متى اختار المستخدم عنصرًا منها، ويمكن للكائنات الأخرى إسناد ما تحتاج من معالجات للاستماع إلى ذلك الحدث. وهكذا.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3490_14" style=""><span class="pln">let eventMixin </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">/**
   *طريقة الانضمام إلى الحدث
   *  menu.on('select', function(item) { ... }
  */</span><span class="pln">
  on</span><span class="pun">(</span><span class="pln">eventName</span><span class="pun">,</span><span class="pln"> handler</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_eventHandlers</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_eventHandlers </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">_eventHandlers</span><span class="pun">[</span><span class="pln">eventName</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">_eventHandlers</span><span class="pun">[</span><span class="pln">eventName</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">this</span><span class="pun">.</span><span class="pln">_eventHandlers</span><span class="pun">[</span><span class="pln">eventName</span><span class="pun">].</span><span class="pln">push</span><span class="pun">(</span><span class="pln">handler</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  </span><span class="com">/**
   * طريقة إلغاء الانضمام إلى الحدث
   *  menu.off('select', handler)
   */</span><span class="pln">
  off</span><span class="pun">(</span><span class="pln">eventName</span><span class="pun">,</span><span class="pln"> handler</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let handlers </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_eventHandlers </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_eventHandlers</span><span class="pun">[</span><span class="pln">eventName</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">handlers</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">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"> handlers</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">handlers</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"> handler</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        handlers</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">
      </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">/**
   * توليد حدث من خلال الاسم والبيانات المعطاة
   *  this.trigger('select', data1, data2);
   */</span><span class="pln">
  trigger</span><span class="pun">(</span><span class="pln">eventName</span><span class="pun">,</span><span class="pln"> </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="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_eventHandlers </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">_eventHandlers</span><span class="pun">[</span><span class="pln">eventName</span><span class="pun">])</span><span class="pln"> </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">// no handlers for that event name</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="com">// call the handlers</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_eventHandlers</span><span class="pun">[</span><span class="pln">eventName</span><span class="pun">].</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">handler </span><span class="pun">=&gt;</span><span class="pln"> handler</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="kwd">this</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="pun">};</span></pre>

<ul>
	<li>
		<code>‎.on(eventName, handler)‎</code> -- يضبط الدالة <code>handler</code> لتُشغّل متى ما حدث الحدث بهذا الاسم. تقنيًا تُخزّن خاصية <code>‎_eventHandlerslrm</code> مصفوفة من دوال المعاملة لكلّ حدث، وتُضيف الدالة إلى القائمة.
	</li>
	<li>
		<code>‎.off(eventName, handler)‎</code> -- يحذف الدالّة <code>handler</code> من القائمة.
	</li>
	<li>
		<code>‎.trigger(eventName, ...args)‎</code> -- يولّد حدث: كلّ المعاملات تُستدعى من <code>‎_eventHandlers[eventName]‎</code> مع قائمة الوسطاء <code>‎...args</code>.
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3490_16" style=""><span class="com">// أنشئ صنف</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Menu</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  choose</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">this</span><span class="pun">.</span><span class="pln">trigger</span><span class="pun">(</span><span class="str">"select"</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="typ">Object</span><span class="pun">.</span><span class="pln">assign</span><span class="pun">(</span><span class="typ">Menu</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">,</span><span class="pln"> eventMixin</span><span class="pun">);</span><span class="pln">

let menu </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Menu</span><span class="pun">();</span><span class="pln">
</span><span class="com">// أضف معالج حدث من أجل أن يستدعى عند الإختيار</span><span class="pln">
</span><span class="pun">*!*</span><span class="pln">
menu</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">"select"</span><span class="pun">,</span><span class="pln"> value </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(`</span><span class="typ">Value</span><span class="pln"> selected</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">value</span><span class="pun">}`));</span><span class="pln">
</span><span class="pun">*/!*</span><span class="pln">
</span><span class="com">// ينطلق الحدث=&gt; يُشغّل المعالج مباشرةً ويعرُض</span><span class="pln">
</span><span class="com">// القيمة المختارة:123</span><span class="pln">
menu</span><span class="pun">.</span><span class="pln">choose</span><span class="pun">(</span><span class="str">"123"</span><span class="pun">);</span></pre>

<p>
	يمكننا الآن أن نحوّل أيّ شيفرة لتتفاعل متى ما اخترنا شيئًا من القائمة بالاستماع إلى الحدث عبر <code>menu.on(...)‎</code>.
</p>

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

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

<p>
	مصطلح <em>المخلوط</em> في البرمجة كائنية التوجّه: صنف يحتوي على توابِع نستعملها في أصناف أخرى.
</p>

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

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

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

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/mixins" rel="external nofollow">Mixins</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">907</guid><pubDate>Mon, 29 Jun 2020 18:04:00 +0000</pubDate></item><item><title>&#x641;&#x62D;&#x635; &#x627;&#x644;&#x623;&#x635;&#x646;&#x627;&#x641; &#x639;&#x628;&#x631; instanceof &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%81%D8%AD%D8%B5-%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-%D8%B9%D8%A8%D8%B1-instanceof-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r906/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_06/66.jpg.1e463516d213a1d8e22b51be000021e4.jpg" /></p>

<p>
	يُتيح لنا المُعامل <code>instanceof</code> (أهو سيرورة من) فحص هل الكائن ينتمي إلى الصنف الفلاني؟ كما يأخذ الوراثة في الحسبان عند الفحص.
</p>

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

<h2>
	معامل instanceof
</h2>

<p>
	صياغته هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_7" style="">
<span class="pln">obj instanceof </span><span class="typ">Class</span></pre>

<p>
	يُعيد المُعامل قيمة <code>true</code> لو كان الكائن <code>obj</code> ينتمي إلى الصنف <code>Class</code> أو أيّ صنف يرثه.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_9" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">();</span><span class="pln">

</span><span class="com">// ‫هل هو كائن من الصنف Rabbit؟</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> rabbit instanceof </span><span class="typ">Rabbit</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_6372_11" style="">
<span class="com">// ‫بدل استعمال class</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</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"> </span><span class="typ">Rabbit</span><span class="pun">()</span><span class="pln"> instanceof </span><span class="typ">Rabbit</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true نعم</span></pre>

<p>
	كما والأصناف المضمّنة مثل المصفوفات <code>Array</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_13" 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 instanceof </span><span class="typ">Array</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"> arr instanceof </span><span class="typ">Object</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true نعم</span></pre>

<p>
	لاحظ كيف أنّ الكائن <code>arr</code> ينتمي إلى صنف الكائنات <code>Object</code> أيضًا، إذ ترث المصفوفات -عبر prototype- الكائناتَ.
</p>

<p>
	عادةً ما يتحقّق المُعامل <code>instanceof</code> من سلسلة prototype عند الفحص. كما يمكننا وضع المنطق الذي نريد لكلّ صنف في التابِع الثابت <code>Symbol.hasInstance</code>.
</p>

<p>
	تعمل خوارزمية <code>obj instanceof Class</code> بهذه الطريقة تقريبًا:
</p>

<ol>
<li>
		<p>
			لو وجدت التابِع الثابت <code>Symbol.hasInstance</code> تستدعيه وينتهي الأمر: <code>Class[Symbol.hasInstance](obj)‎</code>. يُعيد التابِع إمّا <code>true</code> وإمّا <code>false</code>. هكذا نخصّص سلوك المُعامل <code>instanceof</code>.
		</p>

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

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_15" style="">
<span class="com">// ‫ضبط instanceOf للتحقق من الافتراض القائل</span><span class="pln">
</span><span class="com">// ‫بأن كل شيء يملك الخاصية canEat هو حيوان</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">static</span><span class="pln"> </span><span class="pun">[</span><span class="typ">Symbol</span><span class="pun">.</span><span class="pln">hasInstance</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">obj</span><span class="pun">.</span><span class="pln">canEat</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</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"> canEat</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">

alert</span><span class="pun">(</span><span class="pln">obj instanceof </span><span class="typ">Animal</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">
</span><span class="com">// ‫تستدعى Animal[Symbol.hasInstance](obj)‎</span></pre>

		<p>
			 
		</p>
	</li>
	<li>
		<p>
			ليس لأغلب الأصناف التابِع <code>Symbol.hasInstance</code>. في هذه الحالة تستعمل المنطق العادي: يفحص <code>obj instanceOf Class</code> لو كان كائن <code>Class.prototype</code> مساويًا لأحد كائنات prototype في سلسلة كائنات prototype للكائن <code>obj</code>.
		</p>

		<p>
			وبعبارة أخرى ، وازن بينهم واحدًا تلو الآخر:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_17" style="">
<span class="pln">obj</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Class</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">?</span><span class="pln">
obj</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Class</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">?</span><span class="pln">
obj</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Class</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">?</span><span class="pln">
</span><span class="pun">...</span><span class="pln">
</span><span class="com">// ‫لو كانت إجابة أيًا منها true، فتُعيد true</span><span class="pln">
</span><span class="com">// ‫وإلّا متى وصلت نهاية السلسلة أعادت false</span></pre>

		<p>
			في المثال أعلاه نرى <code>rabbit.__proto__ === Rabbit.prototype</code>، بذلك تُعطينا الجواب مباشرةً.
		</p>

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

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_19" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">();</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">rabbit instanceof </span><span class="typ">Animal</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‏(هنا) نعم</span><span class="pln">

</span><span class="com">// rabbit.__proto__ === Rabbit.prototype</span><span class="pln">
</span><span class="com">// rabbit.__proto__.__proto__ === Animal.prototype (تطابق!)</span></pre>

		<p>
			 
		</p>
	</li>
</ol>
<p>
	إليك صورة توضّح طريقة موازنة <code>rabbit instanceof Animal</code> مع <code>Animal.prototype</code>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_06/instanceof.png.d8c44ad93dc27de519e2616c7e32d40f.png" data-fileid="45640" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="45640" data-unique="xunut8rds" src="https://academy.hsoub.com/uploads/monthly_2020_06/instanceof.thumb.png.2dea3f5faad85f934819d5f4c68b0085.png" alt="instanceof.png"></a>
</p>

<p>
	كما وهناك أيضًا التابِع <a href="https://wiki.hsoub.com/JavaScript/Object/isPrototypeOf" rel="external">objA.isPrototypeOf(objB)‎</a>، وهو يُعيد <code>true</code> لو كان الكائن <code>objA</code> في مكان داخل سلسلة prototype للكائن <code>objB</code>. يعني أنّنا نستطيع كتابة الفحص هذا <code>obj instanceof Class</code> هكذا: <code>Class.prototype.isPrototypeOf(obj)‎</code>.
</p>

<p>
	الأمر مضحك إذ أنّ باني الصنف <code>Class</code> نفسه ليس لديه أيّ كلمة عن هذا الفحص! المهم هو سلسلة prototype وكائن <code>Class.prototype</code> فقط.
</p>

<p>
	يمكن أن يؤدّي هذا إلى عواقب مثيرة متى تغيّرت خاصية <code>prototype</code> للكائن بعد إنشائه. طالع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_21" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">();</span><span class="pln">

</span><span class="com">// غيّرنا كائن prototype</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype </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"> rabbit instanceof </span><span class="typ">Rabbit</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// false لا</span></pre>

<h2>
	التابع Object.prototype.toString للأنواع
</h2>

<p>
	نعلم بأنّ الكائنات العادية حين تتحوّل إلى سلاسل نصية تصير <code>[object Object]</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_23" style="">
<span class="pln">let 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">obj</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [object Object]</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">());</span><span class="pln"> </span><span class="com">// كما أعلاه</span></pre>

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

<p>
	تبدو غريبة؟ أليس كذلك؟ لنُزل الغموض.
</p>

<p>
	حسب <a href="https://tc39.github.io/ecma262/#sec-object.prototype.tostring" rel="external nofollow">المواصفة</a>، فيمكننا استخراج التابِع <code>toString</code> المضمّن من الكائن وتنفيذه في سياق أيّ قيمة أخرى نريد، وسيكون ناتجه حسب تلك القيمة.
</p>

<ul>
<li>
		لو كان عددًا، فسيكون <code>[object Number]</code>
	</li>
	<li>
		لو كان قيمة منطقية، فسيكون <code>[object Boolean]</code>
	</li>
	<li>
		لو كان <code>null</code>: ‏<code>[object Null]</code>
	</li>
	<li>
		لو كان <code>undefined</code>: ‏<code>[object Undefined]</code>
	</li>
	<li>
		لو كانت مصفوفة: <code>[object Array]</code>
	</li>
	<li>
		…إلى آخره (ويمكننا تخصيص ذلك).
	</li>
</ul>
<p>
	هيًا نوضّح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_25" style="">
<span class="com">// ننسخ التابِع‫ toString إلى متغير ليسهل عملنا</span><span class="pln">
let objectToString </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">;</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="pun">[];</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> objectToString</span><span class="pun">.</span><span class="pln">call</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">// [object Array] مصفوفة!</span></pre>

<p>
	استعملنا هنا <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/function/call" rel="external nofollow">call</a> كما وضّحنا في درس ”<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D8%B2%D8%AE%D8%B1%D9%81%D8%A7%D8%AA-decorators-%D9%88%D8%A7%D9%84%D8%AA%D9%85%D8%B1%D9%8A%D8%B1-forwarding-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r878/" rel="">المزخرفات والتمرير</a>“ لتنفيذ الدالة <code>objectToString</code> بسياق <code>this=arr</code>.
</p>

<p>
	تفحص خوارزمية <code>toString</code> داخليًا قيمة <code>this</code> وتُعيد الناتج الموافق لها. إليك أمثلة أخرى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_27" style="">
<span class="pln">let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">call</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="com">// [object Number]</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">call</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">// [object Null]</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">call</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="com">// [object Function]</span></pre>

<h3>
	Symbol.toStringTag
</h3>

<p>
	يمكننا تخصيص سلوك التابِع <code>toString</code> للكائنات باستعمال خاصية الكائنات <code>Symbol.toStringTag</code> الفريدة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_29" 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="typ">Symbol</span><span class="pun">.</span><span class="pln">toStringTag</span><span class="pun">]:</span><span class="pln"> </span><span class="str">"User"</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="pln">toString</span><span class="pun">.</span><span class="pln">call</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">// [object User] // لاحظ</span></pre>

<p>
	لأغلب الكائنات الخاصّة بالبيئات خاصية مثل هذه. إليك بعض الأمثلة من المتصفّحات مثلًا:
</p>

<pre class="ipsCode">
// تابِع ‫toStringTag للكائنات والأصناف الخاصّة بالمتصفّحات:
alert( window[Symbol.toStringTag]); // window
alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest

alert( {}.toString.call(window) ); // [object Window]
alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]
</pre>

<p>
	كما نرى فالناتج هو تمامًا ما يقوله <code>Symbol.toStringTag</code> (لو وُجد) بغلاف <code>[object ...‎]</code>.
</p>

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

<p>
	يمكننا استخدام <code>‎{}.toString.call</code> بدلًا من <code>instanceof</code> للكائنات المضمنة في اللغة عندما نريد الحصول على نوع البيانات كسلسلة بدلًا من التحقق منها.
</p>

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

<p>
	لنلخّص ما نعرف عن التوابِع التي تفحص الأنواع:
</p>

<table>
<thead><tr>
<th>
				 
			</th>
			<th>
				يعمل على
			</th>
			<th>
				يُعيد
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				<code>typeof</code>
			</td>
			<td>
				الأنواع الأولية
			</td>
			<td>
				سلسلة نصية
			</td>
		</tr>
<tr>
<td>
				‎<code>{}.toString</code>
			</td>
			<td>
				الأنواع الأولية والكائنات المضمّنة والكائنات التي لها <code>Symbol.toStringTag</code>
			</td>
			<td>
				سلسلة نصية
			</td>
		</tr>
<tr>
<td>
				<code>instanceof</code>
			</td>
			<td>
				الكائنات
			</td>
			<td>
				true/false
			</td>
		</tr>
</tbody>
</table>
<p>
	كما نرى فعبارة <code style="font-size: 16px;">‎{}.toString</code> هي تقنيًا <code style="font-size: 16px;">typeof</code> ولكن ”متقدّمة أكثر“.
</p>

<p>
	بل إن التابع <code>instanceof</code> يؤدي دور مميّز عندما نتعامل مع تسلسل هرمي للأصناف ونريد التحقق من صنفٍ ما مع مراعاة الوراثة.
</p>

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

<h2>
	instnaceof غريب عجيب
</h2>

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

<p>
	في الشيفرة أسفله، لماذا يُعيد <code>instanceof</code> القيمة <code>true</code>. يتّضح جليًا بأنّ <code>B()‎</code> لم يُنشِئ <code>a</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6372_31" style="">
<span class="kwd">function</span><span class="pln"> A</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> B</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">prototype </span><span class="pun">=</span><span class="pln"> B</span><span class="pun">.</span><span class="pln">prototype </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">

</span><span class="com">// هنا</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> a instanceof B </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<h4>
	الحل
</h4>

<p>
	أجل، غريب عجيب حقًا.
</p>

<p>
	ولكن كما نعرف فلا يكترث المُعامل <code>instanceof</code> بالدالة، بل بكائن prototype لها حيث تُطابقه مع غيره في سلسلة prototype.
</p>

<p>
	وهنا نجد <code>a.__proto__ == B.prototype</code>، بذلك يُعيد <code>instanceof</code> القيمة <code>true</code>.
</p>

<p>
	إذًا فحسب منطق <code>instanceof</code>، كائن <code>prototype</code> هو الذي يُعرّف النوع وليس الدالة البانية.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/instanceof" rel="external nofollow">Class checking: "instanceof"‎</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>
]]></description><guid isPermaLink="false">906</guid><pubDate>Wed, 10 Jun 2020 14:39:06 +0000</pubDate></item><item><title>&#x62A;&#x648;&#x633;&#x639;&#x629; &#x627;&#x644;&#x623;&#x635;&#x646;&#x627;&#x641; &#x627;&#x644;&#x645;&#x636;&#x645;&#x646;&#x629; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D8%B3%D8%B9%D8%A9-%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-%D8%A7%D9%84%D9%85%D8%B6%D9%85%D9%86%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r905/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_06/65.jpg.c6971a05b43eb8a4dd247491ef2b60d8.jpg" /></p>

<p>
	يمكننا توسيع الأصناف المضمّنة مثل المصفوفات والخرائط وغيرها. فمثلًا يرث صنف <code>PowerArray</code> من المصفوفة <code>Array</code> الأصيلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3378_7" style="">
<span class="com">// نُضيف تابِعًا آخر إليها (أو أكثر لو أردنا‫)</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">PowerArray</span><span class="pln"> extends </span><span class="typ">Array</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  isEmpty</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">length </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="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="kwd">new</span><span class="pln"> </span><span class="typ">PowerArray</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"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</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">isEmpty</span><span class="pun">());</span><span class="pln"> </span><span class="com">// false</span><span class="pln">

let filteredArr </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">item </span><span class="pun">=&gt;</span><span class="pln"> item </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">filteredArr</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 10, 50</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">filteredArr</span><span class="pun">.</span><span class="pln">isEmpty</span><span class="pun">());</span><span class="pln"> </span><span class="com">// false</span></pre>

<p>
	من الجدير بالملاحظة أن التوابع المضمّنة في اللغة مثل: <code>filter</code> و <code>map</code> وغيرهم، تعيد كائنات جديدة من نفس النوع الموروث بالضبط <code>PowerArray</code>. وذلك لأن التطبيق الداخلي للتوابع يستخدم الباني المخصص لتلك الكائنات. في المثال أعلاه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3378_9" style="">
<span class="pln">arr</span><span class="pun">.</span><span class="pln">constructor </span><span class="pun">===</span><span class="pln"> </span><span class="typ">PowerArray</span></pre>

<p>
	متى استدعينا <code>arr.filter()‎</code> أنشأ التابِع داخليًا مصفوفةً جديدة من النتائج باستعمال <code>arr.constructor</code> ذاتها، وليس المصفوفة العادية <code>Array</code>. هذا أمر رائع جدًا إذ يمكننا استعمال توابِع <code>PowerArray</code> على النتائج أيضًا.
</p>

<p>
	يمكننا حتّى تخصيص هذا السلوك كما نرغب. فنُضيف جالِبًا ثابتًا <code>Symbol.species</code> إلى الصنف. لو كان موجودًا فسيُعيد الباني الذي ستستعمله جافاسكربت داخليًا لإنشاء المدخلات الجديدة في التوابِع <code>map</code> و <code>filter</code> وغيرها.
</p>

<p>
	لو أردنا من التوابِع المضمّنة مثل <code>map</code> و <code>filter</code> - لو أردنا أن تُعيد المصفوفات الطبيعية، فعلينا إعادة صنف <code>Array</code> في رمز <code>Symbol.species</code> هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3378_11" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">PowerArray</span><span class="pln"> extends </span><span class="typ">Array</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  isEmpty</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">length </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// ستستعمل التوابِع المضمّنة هذا الصنف ليكون بانيًا</span><span class="pln">
  </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">get</span><span class="pln"> </span><span class="pun">[</span><span class="typ">Symbol</span><span class="pun">.</span><span class="pln">species</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">
  </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="kwd">new</span><span class="pln"> </span><span class="typ">PowerArray</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"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</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">isEmpty</span><span class="pun">());</span><span class="pln"> </span><span class="com">// false</span><span class="pln">

</span><span class="com">// يصنع التابِع ‫ filter مصفوفةً جديدة باستعمال arr.constructor[Symbol.species]‎ بانيًا</span><span class="pln">
let filteredArr </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">item </span><span class="pun">=&gt;</span><span class="pln"> item </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln">

</span><span class="com">// نوع ‫ filteredArr ليس PowerArray بل Array</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">filteredArr</span><span class="pun">.</span><span class="pln">isEmpty</span><span class="pun">());</span><span class="pln"> </span><span class="com">// Error: filteredArr.isEmpty is not a function</span></pre>

<p>
	كما نرى فالآن يُعيد التابِع ‎<code>.filter</code> مصفوفةً <code>Array</code>. بذلك تلك الميزة الموسّعة لن تُمرّر أكثر وأكثر.
</p>

<p>
	<strong>ملاحظة</strong>: هنالك مجموعات أخرى تعمل بنفس الطريقة مثل: <code>Map</code> أو <code>Set</code> ويستخدمون أيضًا <code>Symbol.species</code>.
</p>

<h2>
	الأنواع المضمّنة لا ترث الثوابت
</h2>

<p>
	للكائنات المضمّنة أيضًا توابِع ثابتة مثل <code>Object.keys</code> و <code>Array.isArray</code> وغيرها.
</p>

<p>
	وكما نعلم فالأصناف الأصيلة تُوسّع نفسها. فمثلًا تُوسّع المصفوفات <code>Array</code> الكائناتَ <code>Object</code>.
</p>

<p>
	وعادةً متى وسّع الصنف صنفًا آخر ورث التوابِع الثابتة وغير الثابتة. شرحنا هذا بالتفصيل في المقال ”<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D8%AB%D8%A7%D8%A8%D8%AA%D8%A9-static-properties-and-methods-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r903/" rel="">الخاصيات والتوابع الثابتة</a>“.
</p>

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

<p>
	مثال: ترث المصفوفات والتواريخ الكائناتَ، بذلك نرى لسيروراتها توابِع أتت من <code>Object.prototype</code>. ولكنّ كائن <code>Array.[[Prototype]]‎</code> لا يُشير إلى <code>Array</code>، بذلك لا نرى توابِع ثابتة مثل <code>Array.keys()‎</code> أو<code>Array.keys()‎</code> مثلًا.
</p>

<p>
	تغني الصورة عن ألف كلمة، إليك واحدة توضّح بنية التواريخ <code>Date</code> والكائنات <code>Object</code>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="45635" href="https://academy.hsoub.com/uploads/monthly_2020_06/object-date-inheritance.png.2d30ac601ea02a34ff4b7b6562c36746.png" rel=""><img alt="object-date-inheritance.png" class="ipsImage ipsImage_thumbnailed" data-fileid="45635" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_06/object-date-inheritance.thumb.png.4bd57bb2cfad62b6a1031ef8db1fbc43.png"></a>
</p>

<p>
	كما ترى فليس هناك رابط بين التواريخ والكائنات، فهي مستقلة بذاتها. كائن <code>Date.prototype</code> فقط هو من يرث <code>Object.prototype</code>.
</p>

<p>
	هذا فرق مهمّ للوراثة بين الكائنات المضمّنة في اللغة وتلك التي نحصل عليها باستعمال <code>extends</code>.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/extend-natives" rel="external nofollow">Extending built-in classes</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">905</guid><pubDate>Wed, 10 Jun 2020 14:21:14 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62E;&#x627;&#x635;&#x64A;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x62A;&#x648;&#x627;&#x628;&#x639; &#x627;&#x644;&#x62E;&#x627;&#x635;&#x629; &#x648;&#x627;&#x644;&#x645;&#x62D;&#x645;&#x64A;&#x629; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D8%A9-%D9%88%D8%A7%D9%84%D9%85%D8%AD%D9%85%D9%8A%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r904/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_06/64.jpg.73fe524fd4cfbb0d23090b1c9c70620a.jpg" /></p>
<p>
	في البرمجة كائنية التوجّه، يُعدّ أكثر المبادئ أهمية هو فصل الواجهة الداخلية عن الخارجية.
</p>

<p>
	هذا المبدأ ”إلزامي“ متى ما طوّرنا تطبيقًا يفوق تطبيقات ”أهلًا يا عالم“ تعقيدًا.
</p>

<p>
	سنضع البرمجة ”على جنب“ ونرى الواقع؛ لنفهم هذا المبدأ.
</p>

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

<h2>
	مثال من الحياة العملية
</h2>

<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>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="45628" href="https://academy.hsoub.com/uploads/monthly_2020_06/coffee.jpg.bb42b40f4ae32af2f0114edcd55e5b3e.jpg" rel="" data-fileext="jpg"><img alt="coffee.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="45628" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_06/coffee.jpg.bb42b40f4ae32af2f0114edcd55e5b3e.jpg"></a>
</p>

<p>
	ولكن من الداخل نرى… (هذه الصورة من كتيّب التصليح)
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="45627" href="https://academy.hsoub.com/uploads/monthly_2020_06/coffee-inside.jpg.6fa9dcbad96b58a7d7324addf9ec214f.jpg" rel="" data-fileext="jpg"><img alt="coffee-inside.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="45627" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_06/coffee-inside.jpg.6fa9dcbad96b58a7d7324addf9ec214f.jpg"></a>
</p>

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

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

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

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

<p>
	كما سنرى أسفله، فالكائنات في البرمجة تشبه تمامًا آلات صنع القهوة.
</p>

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

<h2>
	الواجهتان الداخلية والخارجية
</h2>

<p>
	في البرمجة كائنية التوجّه، تنقسم الخاصيات والتوابِع إلى قسمين:
</p>

<ul>
	<li>
		<em>واجهة داخلية</em> (Internal interface): فيها التوابِع والخاصيات الّتي يمكن أن تصل إليها توابِع هذا الصنف، ولا يمكن أن يصل إليها ما خارج هذا الصنف.
	</li>
	<li>
		<em>واجهة خارجية</em> (External interface): فيها التوابِع والخاصيات الّتي يمكن أن يصل إليها ما خارج هذا الصنف أيضًا.
	</li>
</ul>

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

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

<p>
	شرحنا الآن الفكرة بشكلٍ عام.
</p>

<p>
	أمّا في جافاسكربت فهناك نوعين من حقول الكائنات (الخاصيات والتوابِع):
</p>

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

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

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

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

<h2>
	حماية ”مقدار الماء“
</h2>

<p>
	لنصنع أولًا صنفًا بسيطًا لآلة قهوة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2889_7" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">CoffeeMachine</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  waterAmount </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">

  constructor</span><span class="pun">(</span><span class="pln">power</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">power </span><span class="pun">=</span><span class="pln"> power</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">Created</span><span class="pln"> a coffee</span><span class="pun">-</span><span class="pln">machine</span><span class="pun">,</span><span class="pln"> power</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">power</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">

</span><span class="com">// نصنع آلة قهوة واحدة</span><span class="pln">
let coffeeMachine </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">CoffeeMachine</span><span class="pun">(</span><span class="lit">100</span><span class="pun">);</span><span class="pln">

</span><span class="com">// نُضيف إليها الماء</span><span class="pln">
coffeeMachine</span><span class="pun">.</span><span class="pln">waterAmount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">200</span><span class="pun">;</span></pre>

<p>
	حاليًا فخاصيتي مقدار الماء <code>waterAmount</code> والقوّة <code>power</code> عامّتين، ويمكننا بسهولة جلبهما أو ضبطهما من خارج الصنف لأيّ قيمة نريد.
</p>

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

<p>
	<strong>عادةً ما نضع شَرطة سفلية <code>_</code> قبل أسماء الخاصيات المحميّة.</strong>
</p>

<p>
	لا تفرض اللغة هذا الأمر ولكنّه اتّفاق بين معشر المطوّرين بأنّه ممنوع الوصول إلى هذه الخاصيات والتوابِع من خارج الأصناف.
</p>

<p>
	إذًا، ستكون الخاصية باسم <code>‎_waterAmount</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2889_9" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">CoffeeMachine</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  _waterAmount </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">set</span><span class="pln"> waterAmount</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">value </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">"Negative water"</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">_waterAmount </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">get</span><span class="pln"> waterAmount</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">_waterAmount</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  constructor</span><span class="pun">(</span><span class="pln">power</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">_power </span><span class="pun">=</span><span class="pln"> power</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 coffeeMachine </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">CoffeeMachine</span><span class="pun">(</span><span class="lit">100</span><span class="pun">);</span><span class="pln">

</span><span class="com">// نُضيف الماء</span><span class="pln">
coffeeMachine</span><span class="pun">.</span><span class="pln">waterAmount </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="com">// خطأ: قيمة الماء بالسالب</span></pre>

<p>
	الآن صرنا نتحكّم بالوصول إلى الخاصية، ومحاولة ضبط قيمة الماء إلى ما دون الصفر ستفشل.
</p>

<h2>
	”القوّة“ للقراءة فقط
</h2>

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

<p>
	هذه هي حالة آلة القهوة هنا، إذ قوّة الآلة لا تتغيّر أبدًا.
</p>

<p>
	لذلك سنصنع جالبًا فقط دون ضابِط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2889_11" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">CoffeeMachine</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  constructor</span><span class="pun">(</span><span class="pln">power</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">_power </span><span class="pun">=</span><span class="pln"> power</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">get</span><span class="pln"> power</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">_power</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 coffeeMachine </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">CoffeeMachine</span><span class="pun">(</span><span class="lit">100</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(`</span><span class="typ">Power</span><span class="pln"> is</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">coffeeMachine</span><span class="pun">.</span><span class="pln">power</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">

coffeeMachine</span><span class="pun">.</span><span class="pln">power </span><span class="pun">=</span><span class="pln"> </span><span class="lit">25</span><span class="pun">;</span><span class="pln"> </span><span class="com">// خطأ (لا ضابِط‫)</span></pre>

<p>
	<strong>ملاحظة</strong>:استخدامنا هنا صياغة الجوالِب/الضوابِط (Getter/setter) الإفتراضية ولكن دوالّ <code>get.../set...‎</code> مفضلة في معظم الأحيان. هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2889_13" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">CoffeeMachine</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  _waterAmount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

  setWaterAmount</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">value </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">"Negative water"</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_waterAmount </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">

 getWaterAmount</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">_waterAmount</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">new</span><span class="pln"> </span><span class="typ">CoffeeMachine</span><span class="pun">().</span><span class="pln">setWaterAmount</span><span class="pun">(</span><span class="lit">100</span><span class="pun">);</span></pre>

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

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

<p>
	<strong>ملاحظة</strong>: الخاصيات المحميّة موروثة. إذا ورثنا <code>class MegaMachine extends CoffeeMachine</code>، فلا شيء سيمنعنا من الوصول إلى <code>this._waterAmount</code> أو <code>this._power</code> من توابع الصنف الجديد.
</p>

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

<h2>
	”#حدّ الماء“ خاصّة
</h2>

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

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

<p>
	تبدأ الخاصيات والتوابِع بعلامة <code>#</code>، ولا يمكن الوصول إليها إلّا من داخل الصنف.
</p>

<p>
	فمثلًا إليك خاصية <code>‎#waterLimit</code> الخاصّة وتابِع فحص مستوى الماء <code>‎#checkWater</code> الخاصّ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2889_15" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">CoffeeMachine</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">#</span><span class="pln">waterLimit </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">// هنا</span><span class="pln">

  </span><span class="com">// هذا</span><span class="pln">
  </span><span class="pun">#</span><span class="pln">checkWater</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">value </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">"Negative water"</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">&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.#</span><span class="pln">waterLimit</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">"Too much water"</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 coffeeMachine </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">CoffeeMachine</span><span class="pun">();</span><span class="pln">

</span><span class="com">// محال الوصول إلى الخاصيات والتوابِع الخاصّة من خارج الصنف</span><span class="pln">
coffeeMachine</span><span class="pun">.#</span><span class="pln">checkWater</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Error</span><span class="pln">
coffeeMachine</span><span class="pun">.#</span><span class="pln">waterLimit </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">// Error</span></pre>

<p>
	علامة <code>#</code> على مستوى اللغة هي علامة خاصّة تقول بأنّ هذا الحقل حقلٌ خاصّ، وتمنع أيّ شيء من الوصول إليه من الخارج أو من الأصناف الموروثة.
</p>

<p>
	كما وأنّ الحقول الخاصّة لا تتضارب مع تلك العامّة: يمكن أن نضع حقلين خاصًا <code>‎#waterAmount</code> وعامًا <code>waterAmount</code> في آنٍ واحد.
</p>

<p>
	فمثلًا ليكن <code>waterAmount</code> خاصية وصول للخاصية <code>‎#waterAmount</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2889_17" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">CoffeeMachine</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="pun">#</span><span class="pln">waterAmount </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">get</span><span class="pln"> waterAmount</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">waterAmount</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">set</span><span class="pln"> waterAmount</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">value </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">"Negative water"</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">waterAmount </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">

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

machine</span><span class="pun">.</span><span class="pln">waterAmount </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">machine</span><span class="pun">.#</span><span class="pln">waterAmount</span><span class="pun">);</span><span class="pln"> </span><span class="com">// خطأ</span></pre>

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

<p>
	ولكن لو ورثنا شيئًا من <code>CoffeeMachine</code> فلن يمكننا الوصول إلى <code>‎#waterAmount</code> مباشرةً، بل الاعتماد على جالِب وضابِط <code>waterAmount</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2889_19" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">MegaCoffeeMachine</span><span class="pln"> extends </span><span class="typ">CoffeeMachine</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  method</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">waterAmount </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫خطأ: يمكنك أن تصل إليه من داخل CoffeeMachine فقط</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	<strong>تحذير: لا يمكنك الوصول إلى الحقول الخاصّة هكذا: this[name]‎</strong> إذ عادةً ما يمكننا الوصول إلى الحقول العادية هكذا : this[name]‎
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2889_21" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">User</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><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let fieldName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"name"</span><span class="pun">;</span><span class="pln">
    alert</span><span class="pun">(`</span><span class="typ">Hello</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">fieldName</span><span class="pun">]}`);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ولكن مع الحقول الخاصة من المحال الوصول إليها this['#name']‎ فإنها لن تعمل. وذلك بسبب القيد الموجود على صياغة استدعاء الحقول الخاصة لضمان خصوصية الحقل.
</p>

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

<p>
	لو استعرنا تسميات البرمجة كائنية التوجّه، فعملية فصل الواجهة الداخلية عن الخارجية تُسمّى <a href="https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)" rel="external nofollow">تغليف</a> (Encapsulation)، وهي تقدّم لنا فوائد منها:
</p>

<ul>
	<li>
		<p>
			<strong>حماية المستخدمين كي لا يضروا أنفسهم</strong>: تخيّل فريق مطوّرين يستعمل آلةً للقهوة صنعتها شركة ”Best CoffeeMachine“، وهي تعمل كما يجب لكنّها دون غطاء حماية، أيّ أنّ الواجهة الداخلية مكشوفة للعيان.
		</p>

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

		<p>
			هذه ليست غلطة John طبعًا، بل الشخص الّذي أزال غطاء الحماية وسمح لأشخاص (مثل John) أن يقوموا بهذه التعديلات.
		</p>

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

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

		<p>
			وليس المبرمج استثناءً
		</p>

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

<p>
	حاليًا فالحقول الخاصّة ليست مدعومة تمامًا في المتصفّحات، ولكن يمكننا تعويض نقص الدعم هذا.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/private-protected-properties-methods" rel="external nofollow">Private and protected properties and methods</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">904</guid><pubDate>Thu, 18 Jun 2020 18:02:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62E;&#x627;&#x635;&#x64A;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x62A;&#x648;&#x627;&#x628;&#x639; &#x627;&#x644;&#x62B;&#x627;&#x628;&#x62A;&#x629; (Static properties and methods) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D8%AB%D8%A7%D8%A8%D8%AA%D8%A9-static-properties-and-methods-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r903/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_06/63.jpg.919e57c8f258b39a4fe1c5bc767086a0.jpg" /></p>

<p>
	يمكننا أيضًا إسناد التوابِع إلى دالة الصنف ذاتها وليس إلى كائن <code>"prototype"</code> لها. نسمّي هذه التوابِع بالتوابِع ”الثابتة“ (static).
</p>

<p>
	في الأصناف نضع بعدها كلمة <code>static</code> هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3058_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">static</span><span class="pln"> staticMethod</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="kwd">this</span><span class="pln"> </span><span class="pun">===</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">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">staticMethod</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_3058_9" style="">
<span class="kwd">class</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"> </span><span class="pun">}</span><span class="pln">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">staticMethod </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="pln"> </span><span class="pun">===</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">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">staticMethod</span><span class="pun">();</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	وتكون قيمة <code>this</code> في الاستدعاء <code>User.staticMethod()‎</code> هي باني الصنف <code>User</code> ذاته (تذكّر قاعدة ”الكائن قبل النقطة“),
</p>

<p>
	عادةً ما نستعمل التوابِع الثابتة لكتابة دوال تعود إلى الصنف نفسه وليس إلى أيّ كائن من ذلك الصنف.
</p>

<p>
	مثال للتوضيح: لدينا كائنات مقالات <code>Article</code> ونريد دالة لموازنتها. الحل الطبيعي هو إضافة تابِع <code>Article.compare</code> هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3058_11" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Article</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">title</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="kwd">this</span><span class="pun">.</span><span class="pln">title </span><span class="pun">=</span><span class="pln"> title</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</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">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// هنا</span><span class="pln">
  </span><span class="kwd">static</span><span class="pln"> compare</span><span class="pun">(</span><span class="pln">articleA</span><span class="pun">,</span><span class="pln"> articleB</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"> articleA</span><span class="pun">.</span><span class="pln">date </span><span class="pun">-</span><span class="pln"> articleB</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="pun">}</span><span class="pln">

</span><span class="com">// الاستعمال</span><span class="pln">
let articles </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">Article</span><span class="pun">(</span><span class="str">"HTML"</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">2019</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="kwd">new</span><span class="pln"> </span><span class="typ">Article</span><span class="pun">(</span><span class="str">"CSS"</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">2019</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="kwd">new</span><span class="pln"> </span><span class="typ">Article</span><span class="pun">(</span><span class="str">"JavaScript"</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">2019</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">))</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

articles</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="typ">Article</span><span class="pun">.</span><span class="pln">compare</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"> articles</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">title </span><span class="pun">);</span><span class="pln"> </span><span class="com">// CSS</span></pre>

<p>
	نرى هنا التابِع <code>Article.compare</code> ”فوق“ المقالات فيتيح لنا طريقة لموازنتها. ليس التابِع تابِعًا للمقالة ذاتها، بل لصنف المقالات نفسه.
</p>

<p>
	توابِع ”المصانع“ (factory) تنفعها أيضًا التوابِع الثابتة هذه. لنقل بأنّا نريد إنشاء المقالات بطرائق عدّة:
</p>

<ol>
<li>
		بتمرير المُعاملات (العنوان <code>title</code> والتاريخ <code>date</code> وغيرها).
	</li>
	<li>
		إنشاء مقالة فارغة تحمل تاريخ اليوم.
	</li>
	<li>
		أو… كما تريد أنت.
	</li>
</ol>
<p>
	يمكننا تنفيذ الطريقة الأولى باستعمال بانٍ، وللثانية صناعة تابِع ثابت للصنف.
</p>

<p>
	مثل التابِع <code>Article.createTodays()‎</code> هنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3058_13" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Article</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">title</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="kwd">this</span><span class="pun">.</span><span class="pln">title </span><span class="pun">=</span><span class="pln"> title</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</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">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">static</span><span class="pln"> createTodays</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// لا تنسَ: this = Article</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="kwd">this</span><span class="pun">(</span><span class="str">"Today's digest"</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="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let article </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Article</span><span class="pun">.</span><span class="pln">createTodays</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> article</span><span class="pun">.</span><span class="pln">title </span><span class="pun">);</span><span class="pln"> </span><span class="com">// موجز أحداث اليوم</span></pre>

<p>
	الآن متى أردنا صناعة موجز عن أحداث اليوم، استدعينا <code>Article.createTodays()‎</code>. أُعيد، ليس هذا تابِعًا للمقالة نفسها بل تابِعًا للصنف كله.
</p>

<p>
	كما نستعمل التوابِع الثابتة في أصناف قواعد البيانات للبحث عن المُدخلات وحفظها وإزالتها، هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3058_15" style="">
<span class="com">// بفرض أنّ ‫ Article هو صنف مخصّص لإدارة المقالات</span><span class="pln">
</span><span class="com">// نستعمل تابِعًا ثابتًا لإزالة المقالة:</span><span class="pln">
</span><span class="typ">Article</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">({</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">12345</span><span class="pun">});</span></pre>

<h2>
	الخاصيات الثابتة
</h2>

<p>
	<strong>إضافة حديثة</strong>
</p>

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

<p>
	كما يمكننا أيضًا استعمال الخاصيات الثابتة. ظاهرها فهي خاصيات للأصناف، ولكن نضع قبلها عبارة <code>static</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3058_17" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Article</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">static</span><span class="pln"> publisher </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Ilya Kantor"</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="typ">Article</span><span class="pun">.</span><span class="pln">publisher </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Ilya Kantor</span></pre>

<p>
	لا يفرق هذا عن الإسناد المباشر إلى صنف <code>Article</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3058_19" style="">
<span class="typ">Article</span><span class="pun">.</span><span class="pln">publisher </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Ilya Kantor"</span><span class="pun">;</span></pre>

<h2>
	وراثة الخاصيات والتوابِع الثابتة
</h2>

<p>
	هذه الأنواع من الخاصيات والتوابِع
</p>

<p>
	فمثلًا التابِع <code>Animal.compare</code> والخاصية <code>Animal.planet</code> في الشيفرة أسفله موروثين بالأسماء <code>Rabbit.compare</code> و <code>Rabbit.planet</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3058_21" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">static</span><span class="pln"> planet </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Earth"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// الأرض</span><span class="pln">

  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> speed</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">speed </span><span class="pun">=</span><span class="pln"> speed</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">

  run</span><span class="pun">(</span><span class="pln">speed </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">speed </span><span class="pun">+=</span><span class="pln"> speed</span><span class="pun">;</span><span class="pln">
    alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> runs </span><span class="kwd">with</span><span class="pln"> speed $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">speed</span><span class="pun">}.`);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">static</span><span class="pln"> compare</span><span class="pun">(</span><span class="pln">animalA</span><span class="pun">,</span><span class="pln"> animalB</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"> animalA</span><span class="pun">.</span><span class="pln">speed </span><span class="pun">-</span><span class="pln"> animalB</span><span class="pun">.</span><span class="pln">speed</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">// نرث من الصنف Animal</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  hide</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="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> hides</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 rabbits </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">Rabbit</span><span class="pun">(</span><span class="str">"White Rabbit"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">),</span><span class="pln">
  </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"Black Rabbit"</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">

rabbits</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">compare</span><span class="pun">);</span><span class="pln"> </span><span class="com">// لاحظ</span><span class="pln">

rabbits</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">run</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Black Rabbit runs with speed 5.</span><span class="pln">

alert</span><span class="pun">(</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">planet</span><span class="pun">);</span><span class="pln"> </span><span class="com">// الأرض</span></pre>

<p>
	الآن متى استدعينا <code>Rabbit.compare</code>، استدعى المحرّك التابِع <code>Animal.compare</code> الموروث.
</p>

<p>
	ولكن كيف يعمل هذا الشيء؟ كالعادة، بكائنات prototype: تُقدّم <code>extends</code> للصنف <code>Rabbit</code> إشارة <code>[[Prototype]]</code> إلى الصنف <code>Animal</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_06/animal-rabbit-static.png.31ed85c0a77933214e4f2d652e99adf5.png" data-fileid="45622" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="45622" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_06/animal-rabbit-static.thumb.png.4d22129f66f825d7b3f9bed0ada7f06f.png" alt="animal-rabbit-static.png"></a>
</p>

<p>
	لذا فعبارة <code>Rabbit extends Animal</code> تصنع إشارتي <code>[[Prototype]]</code>:
</p>

<ol>
<li>
		دالة <code>Rabbit</code> موروثة عبر prototype من دالة <code>Animal</code>.
	</li>
	<li>
		كائن <code>Rabbit.prototype</code> موروث عبر prototype من كائن <code>Animal.prototype</code>.
	</li>
</ol>
<p>
	بهذا تعمل الوراثة للتوابِع العادية والثابتة معًا.
</p>

<p>
	تشكّ؟ انظر للشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3058_23" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</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="typ">Rabbit</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Animal</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">
alert</span><span class="pun">(</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Animal</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

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

<p>
	نستعمل التوابِع الثابتة لأيّة وظائف تخصّ الصنف ”كلّه على بعضه“، ولا يخصّ سيرورة معيّنة من الصنف.
</p>

<p>
	مثل تابع الموازنة <code>Article.compare(article1, article2)‎</code> أو تابع المصنع <code>Article.createTodays()‎</code>.
</p>

<p>
	ويصنفون كثوابت (<code>static</code>) في تعريف الصنف.
</p>

<p>
	نستعمل الخاصيات الثابتة متى أردنا تخزين البيانات على مستوى الصنف لا على مستوى السيرورات.
</p>

<p>
	صياغتها هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3058_25" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">MyClass</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">static</span><span class="pln"> property </span><span class="pun">=</span><span class="pln"> </span><span class="pun">...;</span><span class="pln">

  </span><span class="kwd">static</span><span class="pln"> method</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>
	تقنيًا فالتصريح الثابت (static declaration) لا يفرق عن الإسناد إلى الصنف مباشرةً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3058_27" style="">
<span class="typ">MyClass</span><span class="pun">.</span><span class="pln">property </span><span class="pun">=</span><span class="pln"> </span><span class="pun">...</span><span class="pln">
</span><span class="typ">MyClass</span><span class="pun">.</span><span class="pln">method </span><span class="pun">=</span><span class="pln"> </span><span class="pun">...</span></pre>

<p>
	الخاصيات والدوال الثابتة الموروثة.
</p>

<p>
	من أجل العبارة <code>class B extends A</code> إن prototype للصنف <code>B</code> يشير إلى <code>A</code>:<code>B.[[Prototype]] = A</code>. لذا إن تعذر العثور على خاصية ما في الصنف <code>B</code> فسيستمر البحث في الصنف <code>A</code>.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/static-properties-methods" rel="external nofollow">Static properties and methods</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">903</guid><pubDate>Wed, 10 Jun 2020 13:46:52 +0000</pubDate></item><item><title>&#x648;&#x631;&#x627;&#x62B;&#x629; &#x627;&#x644;&#x623;&#x635;&#x646;&#x627;&#x641; (Class inheritance) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%88%D8%B1%D8%A7%D8%AB%D8%A9-%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-class-inheritance-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r902/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_06/62.jpg.35845f6eaa9a4bc597cc5d5dabf43311.jpg" /></p>

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

<h2>
	عبارة التوسعة <code>extends</code>
</h2>

<p>
	لنقل بأنّ لدينا صنف الحيوان <code>Animal</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">speed </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">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">
  run</span><span class="pun">(</span><span class="pln">speed</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">speed </span><span class="pun">+=</span><span class="pln"> speed</span><span class="pun">;</span><span class="pln">
    alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> runs </span><span class="kwd">with</span><span class="pln"> speed $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">speed</span><span class="pun">}.`);</span><span class="pln"> </span><span class="com">// يركض حيوان كذا بالسرعة كذا</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  stop</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">speed </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">$</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"> stands still</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 animal </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Animal</span><span class="pun">(</span><span class="str">"My animal"</span><span class="pun">);</span></pre>

<p>
	هكذا نصف كائن الحيوان <code>animal</code> وصنف الحيوان <code>Animal</code> في صورة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_06/rabbit-animal-independent-animal.png.b879e149e3f13761f2443e1432f0cf3f.png" data-fileid="45616" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="45616" data-unique="jpzdhgkzk" src="https://academy.hsoub.com/uploads/monthly_2020_06/rabbit-animal-independent-animal.thumb.png.9e30add49c6e93b850174e9eeb961fd0.png" alt="rabbit-animal-independent-animal.png"></a>
</p>

<p>
	ولنقل بأنّنا نريد إضافة صنف آخر… ليكن أرنبًا <code>class Rabbit</code>.
</p>

<p>
	وطبعًا، فالأرانب حيوانات أيضًا، وعلى صنف الأرانب <code>Rabbit</code> أن يكون أساسه الحيوان <code>Animal</code> ليصل إلى توابِع الحيوانات فتقوم الأرانب بما تقوم به الحيوانات ”العادية“ (generic).
</p>

<p>
	صياغة توسعة الصنف إلى صنف آخر هي: <code>class Child extends Parent</code> (صنف الابن توسعة من صنف الأبّ).
</p>

<p>
	لنصنع صنف الأرنب <code>class Rabbit</code> ليرث الحيوان <code>Animal</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_9" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// لاحظ</span><span class="pln">
  hide</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="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> hides</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 rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"White Rabbit"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// الأرنب الأبيض</span><span class="pln">

rabbit</span><span class="pun">.</span><span class="pln">run</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln"> </span><span class="com">// White Rabbit runs with speed 5. // يركض حيوان الأرنب بسرعة 5</span><span class="pln">
rabbit</span><span class="pun">.</span><span class="pln">hide</span><span class="pun">();</span><span class="pln"> </span><span class="com">// White Rabbit hides! // اختفى الأرنب الأبيض!</span></pre>

<p>
	يمكن لكائن <code>Rabbit</code> الوصول إلى توابِع <code>Rabbit</code> (مثل <code>rabbit.hide()</code>) كما توابِع <code>Animal</code> (مثل <code>rabbit.run()</code>).
</p>

<p>
	داخليًا فعبارة <code>extends</code> تعمل كما تعمل ميكانيكية كائنات prototype المعهودة، فضتبط <code>Rabbit.prototype.[[Prototype]]‎</code> ليكون <code>Animal.prototype</code>. بهذا لو لم يوجد التابِع في كائن <code>Rabbit.prototype</code>، يأخذه المحرّك من <code>Animal.prototype</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_06/animal-rabbit-extends.png.70b5c571309a85603cc4b2eca60ce4ad.png" data-fileid="45615" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="45615" data-unique="k80adhu6l" src="https://academy.hsoub.com/uploads/monthly_2020_06/animal-rabbit-extends.thumb.png.a0ba2311d8006ddf92fdd6c9b74fd6bf.png" alt="animal-rabbit-extends.png"></a>
</p>

<p>
	فمثلًا لنجد التابِع <code>rabbit.run</code> يبحث المحرّك (من أسفل إلى أعلى، كما الصورة):
</p>

<ol>
<li>
		كائن الأرنب <code>rabbit</code> (ليس فيه <code>run</code>).
	</li>
	<li>
		كائن prototype له، أي <code>Rabbit.prototype</code> (فيه <code>hide</code> وليس فيه <code>run</code>).
	</li>
	<li>
		كائن prototype له، أي (بسبب <code>extends</code>) ‏<code>Animal.prototype</code>، بهذا يجد تابِع <code>run</code> أخيرًا.
	</li>
</ol>
<p>
	كما نذكر من فصل ”“، فمحرّك جافاسكربت نفسه يستعمل التوارث عبر prototype لكائناته المضمّنة في اللغة. فمثلًا كائن <code>Date.prototype.[[Prototype]]‎</code> هو الكائن <code>Object.prototype</code>. لهذا يمكن للتواريخ الوصول إلى توابِع الكائنات العادية.
</p>

<p>
	<strong>ملاحظة</strong>: تسمح صياغة الصنف ليس بتحديد الصنف فقط وإنما إضافة أي تعبير بعد عبارة <code>extends</code>. فمثلًا استدعاء التابع التاي سيبني صنف الأب.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_11" style="">
<span class="kwd">function</span><span class="pln"> f</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">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">class</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"> 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">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> extends f</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="kwd">new</span><span class="pln"> </span><span class="typ">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>class User</code> من النتيجة للصنف <code>f("Hello")‎</code>.
</p>

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

<h2>
	إعادة تعريف دالة
</h2>

<p>
	الآن نتحرّك ونعيد تعريف أحد التوابِع. مبدئيًا فكلّ التوابِع غير المحدّدة في صنف الأرانب تُؤخذ مباشرةً ”كما هي“ من صنف الحيوانات.
</p>

<p>
	ولكن لو حدّدنا تابِعًا معيّنًا في في <code>Rabbit</code> (وليكن <code>stop()‎</code>) فسيُستعمل بدله:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_13" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  stop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// الآن سنسخدمها من أجل ‫rabbit.stop‪()</span><span class="pln">
</span><span class="com">// بدلًا من استخدام ‫stop()‎ من الصنف مباشرة</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>
	ولحسن الحظ فالأصناف تقدّم لنا عبارة <code>"super"</code>.
</p>

<ul>
<li>
		نستعمل <code>super.method(...)‎</code> لنستدعي تابِعًا أبًا.
	</li>
	<li>
		ونستدعي <code>super(...)‎</code> لنستدعي الباني الأب (هذا فقط لو كنّا في باني هذه الدالة).
	</li>
</ul>
<p>
	فمثلًا، ليختبئ هذا الأرنب النبه ما إن يتوقّف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_15" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">speed </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">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">

  run</span><span class="pun">(</span><span class="pln">speed</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">speed </span><span class="pun">+=</span><span class="pln"> speed</span><span class="pun">;</span><span class="pln">
    alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> runs </span><span class="kwd">with</span><span class="pln"> speed $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">speed</span><span class="pun">}.`);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  stop</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">speed </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">$</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"> stands still</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">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  hide</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="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> hides</span><span class="pun">!`);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// هنا</span><span class="pln">
  stop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</span><span class="pun">.</span><span class="pln">stop</span><span class="pun">();</span><span class="pln"> </span><span class="com">// نستدعي ‫stop في الأب</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">hide</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ثمّ نستدعي ‫hide</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"White Rabbit"</span><span class="pun">);</span><span class="pln">

rabbit</span><span class="pun">.</span><span class="pln">run</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln"> </span><span class="com">// سيركض ‫ "White Rabbit" بسرعة 5</span><span class="pln">
rabbit</span><span class="pun">.</span><span class="pln">stop</span><span class="pun">();</span><span class="pln"> </span><span class="com">// توقف الأرنب .وهو الآن مختبئ</span></pre>

<p>
	الآن صار داخل الأرنب التابِع <code>Rabbit</code> الذي يستدعي التابِع <code>stop</code> من أباه
</p>

<p>
	كما شرحنا في درس "<a href="https://academy.hsoub.com/programming/javascript/%D9%86%D8%B8%D8%B1%D8%A9-%D8%AA%D9%81%D8%B5%D9%8A%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B3%D9%87%D9%85%D9%8A%D8%A9-arrow-functions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r880/" rel="">الدوال السهمية</a>" <strong>لا يمكننا استخدام الكلمة المفتاحية <code>super</code> على الدوالّ السهمية</strong>.
</p>

<p>
	ولو استطعنا الوصول إليها من خلال الكلمة المفتاحية <code>super</code> فستكون مأخوذة من الدالّة الخارجية. هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_17" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  stop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> super</span><span class="pun">.</span><span class="pln">stop</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">
</span><span class="pun">}</span></pre>

<p>
	إن عمل الدلّة <code>stop()‎</code> مشابه تمامًا لعمل الكلمة المفتاحية <code>super</code> مع الدوال السهمية. لذا فإنها تعمل مثلما نريد. ولو حُددت كدالّة عادية فسيظهر لدينا خطأ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_19" style="">
<span class="com">// Unexpected super</span><span class="pln">
setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> super</span><span class="pun">.</span><span class="pln">stop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">},</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span></pre>

<h2>
	إعادة تعريف الباني
</h2>

<p>
	متى تعاملنا مع البانيات، صار الأمر
</p>

<p>
	لم يكن لصنف الأرنب <code>Rabbit</code> (حتّى اللحظة) أيّ بانٍ له.
</p>

<p>
	حسبما تقول <a href="https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation" rel="external nofollow">المواصفة</a> فلو وسّع أحد الأصناف صنفًا آخر ليس له بانيًا، فسيُولّد المحرّك هذا الباني ”الفارغ“:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_21" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// يُولّد للأصناف التي تُوسِّع أخرى وليس فيها بانيات</span><span class="pln">
  constructor</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">
    super</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="pun">}</span></pre>

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

<p>
	لنُضف الآن بانيًا من عندنا إلى الأرنب <code>Rabbit</code>. سيضبط هذا الباني الخاصية <code>earLength</code> علاوةً على <code>name</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_23" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">speed </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">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// هنا  constructor(name, earLength) {</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">speed </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">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">earLength </span><span class="pun">=</span><span class="pln"> earLength</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">
let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"White Rabbit"</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">// Error: this is not defined.</span></pre>

<p>
	ماذا؟! هناك خطأ! انتهى الأمر، ”صناعة الأرانب“ لم تعد ممكنة بعد الآن. تراه ما المشكلة؟
</p>

<p>
	باختصار: على البانيات في الأصناف الموروثة استدعاء <code>super(...)‎</code> هذا أولًا، وثانيًا استدعاءه قبل استعمال <code>this</code>.
</p>

<p>
	ولكن لحظة… لماذا؟ ما الذي يجري؟ هذا المطلب غريب حقًا.
</p>

<p>
	بالطبع لا شيء بدون توضيح وشرح، لذا فلنتعمّق داخل التفاصيل ونفهم ما يجري ”حبّة حبّة“.
</p>

<p>
	تضع لغة جافاسكربت خطًا فاصلًا بين الدالة البانية للصنف الموروث (أي ”الباني المشتقّ“) وغيرها من دوال. لهذا الباني خاصية داخلية فريدة اسمها <code>‎[[ConstructorKind]]:"derived"</code>‎، وهي علامة يضعها المحرّك عليه داخليًا خلف الكواليس. تؤثّر هذه ”العلامة“ على سلوك الباني حين نستعمله مع <code>new</code>.
</p>

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

<p>
	على باني الصنف <code>Rabbit</code> استدعاء <code>super()‎</code> قبل <code>this</code> ليعمل، هكذا تمامًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_25" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">speed </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">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

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

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> earLength</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</span><span class="pun">(</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// هنا</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">earLength </span><span class="pun">=</span><span class="pln"> earLength</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">
let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"White Rabbit"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">rabbit</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// White Rabbit</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">rabbit</span><span class="pun">.</span><span class="pln">earLength</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 10</span></pre>

<h2>
	عبارة <code>super</code>: أمور داخلية و[[HomeObject]]
</h2>

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

<p>
	هيًا ننزل إلى الأعماق ونرى ما خلف كواليس <code>super</code>. في هذه الرحلة سنرى أمور جميلة أيضًا ”إكسترا سوبر“.
</p>

<p>
	لنوضّحها من البداية: لو أخذت كلّ ما تعلّمناه حتّى الحظة، فما من طريقة لتعمل فيها عبارة <code>super</code> في أيّ حال من الأحوال!
</p>

<p>
	تمامًا، كما فكّرت الآن، لنطرح السؤال: كيف تعمل هذه العبارة تقنيًا أساسًا؟ متى ما عمل أحد توابِع الكائنات، جلب الكائن الحالي على أنّه <code>this</code>. فلو استدعينا <code>super.method()‎</code> فكلّ ما على المحرّك فعله هو جلب التابِع <code>method</code> من كائن prototype للكائن الحالي، صحيح؟ أجل ولكن كيف ذلك؟
</p>

<p>
	ربّما ترى المهمة سهلة ولكنّها ليست كذلك البتة. يمكن القول أنّ المحرّك يعلم بالكائن الحالي <code>this</code>، فيمكنه أن يأخذ تابِع <code>method</code> في الأب باستعمال <code>this.__proto__.method</code>. ولكن للأسف فهذا الحلّ ”البسيط“ لن يعمل أبدًا.
</p>

<p>
	لنوضّح المشكلة أولًا، باستعاضة الأصناف لتكون كائنات عادية لتسهيل الفهم.
</p>

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

<p>
	في المثال أسفله، نرى <code>rabbit.__proto__ = animal</code>. لنجرّب الآن هذا الأمر: داخل <code>rabbit.eat()‎</code> نستدعي <code>animal.eat()‎</code> باستعمال <code>this.__proto__‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_27" style="">
<span class="pln">let animal </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">"Animal"</span><span class="pun">,</span><span class="pln">
  eat</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="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> eats</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 rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal</span><span class="pun">,</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Rabbit"</span><span class="pun">,</span><span class="pln">
  eat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// هذه إحدى طرق عمل super.eat()</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="kwd">this</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">

rabbit</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Rabbit eats.</span></pre>

<p>
	أخذنا في السطر <code>(*)</code> التابِعَ <code>eat</code> من كائن prototype ‏(<code>animal</code>) واستدعيناه على أنّ السياق هو الكائن الحالي. لاحظ أهمية <code>‎.call(this)‎</code> إذ لو كتبنا <code>this.__proto__.eat()‎</code> فقط فسيُنفّذ التابِع <code>eat</code> الأب داخل سياق كائنَ prototype، وليس في الكائن الحالي.
</p>

<p>
	وفي الجزء الأول من الشيفرة نرى كلّ شيء يعمل: عمل التابِع <code>alert</code> كما ينبغي عليه.
</p>

<p>
	حان وقت إضافة كائن آخر إلى السلسلة، وكسر هذه السلسلة إربًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_29" style="">
<span class="pln">let animal </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">"Animal"</span><span class="pun">,</span><span class="pln">
  eat</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="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> eats</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 rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal</span><span class="pun">,</span><span class="pln">
  eat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...هنا يأكل الأرنب كما تأكل الأرانب، بعدها نستدعي التابِع الأبّ (animal)</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="kwd">this</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 longEar </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> rabbit</span><span class="pun">,</span><span class="pln">
  eat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...الأرنب ذو الأذن الطويلة يلهو ويلعب، ثمّ نستدعي التابِع الأبّ (rabbit)</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (**)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// هنا!longEar.eat(); // Error: Maximum call stack size exceeded</span></pre>

<p>
	لم تعد الشيفرة تعمل الآن! نرى خطأً عند استدعاء <code>longEar.eat()‎</code>.
</p>

<p>
	قد لا يبدو الأمر جليًا من أوّل نظرة، ولكن لو تعقّبنا استدعاء <code>longEar.eat()‎</code> فسنرى الأمر بوضوح، ففي السطرين (<em>) و (</em>*) تكون قيمة <code>this</code> هي الكائن الحالي (<code>longEar</code>). هذا ضمن الأساسيات، فعلى توابِع الكائنات جلب الكائن الحالي فهو <code>this</code>، وليس كائنَ prototype أو ما شابهه.
</p>

<p>
	بذلك في السطرين معًا (*) و (**) تكون قيمة <code>this.__proto__‎</code> واحدة: الكائن <code>rabbit</code>، وكلاهما يستدعيان التابِع <code>rabbit.eat</code> دون أن يرتقيا بالسلسلة، فيدوران في حلقة لا نهاية لها.
</p>

<p>
	إليك عمّا يحدث في صورة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_06/this-super-loop.png.21a7685fe50be71543f7d2dc989638ae.png" data-fileid="45617" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="45617" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_06/this-super-loop.thumb.png.a8f65fea4a4a46156a06907e3bbcfd52.png" alt="this-super-loop.png"></a>
</p>

<p>
	نرى في التابِع <code>longEar.eat()‎</code> عند السطر <code>(**)</code> استدعاء <code>rabbit.eat</code> بتمرير <code>this=longEar</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_31" style="">
<span class="pln">    </span><span class="com">// نرى داخل ‫ longEar.eat()‎ قيمة this = longEar</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="com">// (**)</span><span class="pln">
    </span><span class="com">// يصير</span><span class="pln">
    longEar</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">)</span><span class="pln">
    </span><span class="com">// وهو فعليًا</span><span class="pln">
    rabbit</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">);</span></pre>

<ol start="2">
<li>
		وبعدها في السطر <code>(*)</code> داخل <code>rabbit.eat</code>، نحاول تمرير الاستدعاء إلى مستوًى أعلى داخل السلسلة، ولكن قيمة <code>this=longEar</code>، بهذا تصير قيمة <code>this.__proto__.eat</code> هي <code>rabbit.eat</code> ثانيةً.
	</li>
</ol>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_33" style="">
<span class="pln">    </span><span class="com">// نرى داخل ‫ rabbit.eat()‎ قيمة this = longEar</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
    </span><span class="com">// becomes</span><span class="pln">
    longEar</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">)</span><span class="pln">
    </span><span class="com">// or (again)</span><span class="pln">
    rabbit</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">);</span></pre>

<ol start="3">
<li>
		بهذا… يستدعي <code>rabbit.eat</code> نفسه في حلقة لانهاية لها لأنّها يعجز عن الارتقاء في السلسلة.
	</li>
</ol>
<p>
	ما من طريقة لحلّ هذه المشكلة باستعمال <code>this</code> فقط.
</p>

<h3>
	<code>[[HomeObject]]</code>
</h3>

<p>
	أضافت لغة جافاسكربت -لحلّ هذه المعضلة- خاصية داخلية (أخرى) للدوال، وهي ”الكائن المنزل“ <code>[[HomeObject]]</code>.
</p>

<p>
	متى ما حُدّدت الدالة لتكون صنفًا أو تابِعًا لكائن، أصبحت خاصية <code>[[HomeObject]]</code> للدالة ذلك الصنف أو الكائن.
</p>

<p>
	تستعمل <code>super</code> هذا الكائن لحلّ كائن prototype الأبّ هو وتوابِعه.
</p>

<p>
	لنرى كيف يعمل هذا الشيء، بالكائنات العادية أولًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_35" style="">
<span class="pln">let animal </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">"Animal"</span><span class="pun">,</span><span class="pln">
  eat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">         </span><span class="com">// animal.eat.[[HomeObject]] == animal</span><span class="pln">
    alert</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> eats</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 rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal</span><span class="pun">,</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Rabbit"</span><span class="pun">,</span><span class="pln">
  eat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">         </span><span class="com">// rabbit.eat.[[HomeObject]] == rabbit</span><span class="pln">
    super</span><span class="pun">.</span><span class="pln">eat</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 longEar </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> rabbit</span><span class="pun">,</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Long Ear"</span><span class="pun">,</span><span class="pln">
  eat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">         </span><span class="com">// longEar.eat.[[HomeObject]] == longEar</span><span class="pln">
    super</span><span class="pun">.</span><span class="pln">eat</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">
longEar</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">();</span><span class="pln">  </span><span class="com">// Long Ear eats.</span></pre>

<p>
	عملت الشيفرة كما المفترض ذلك بسبب آلية عمل <code>[[HomeObject]]</code>. تعرف التوابِع (مثل <code>longEar.eat</code>) خاصيةَ <code>[[HomeObject]]</code> لها وتأخذ التابِع الأبّ من كائن prototype لذاك الكائن، ودون استعمال <code>this</code> أبدًا.
</p>

<h3>
	التوابِع ليست ”حرّة“
</h3>

<p>
	كما نعلم فالتوابع -بنحوٍ عام- ”حرّة“ وليست مروبطة بأيّ كائن. فيمكننا نسخها بين الكائنات واستعمالها بتمرير قيمة <code>this</code> أخرى.
</p>

<p>
	ولكن وجود <code>[[HomeObject]]</code> يخلّ بهذا المبدأ إذ تتذكّر التوابِع كائناتها الأصلية هكذا. يبقى هذا الارتباط وثيقًا للأبد إذ لا يمكننا تغيير <code>[[HomeObject]]</code>.
</p>

<p>
	ولكن المكان الوحيد الذي نستعمل فيه خاصية <code>[[HomeObject]]</code> (في لغة جافاسكربت) هو <code>super</code>. يعني أنّه لو لم يستعمل التابِع <code>super</code> فيمكننا عدّه حرًا ونمضي بنسخه وتوزيعه على الكائنات. ولكن متى استعملت <code>super</code>، ساءت الأمور.
</p>

<p>
	إليك مثالًا كاملًا عن نتيجة خطأ بعد النسخ بسبب <code>super</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7936_37" style="">
<span class="pln">let animal </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">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="pln">I</span><span class="str">'</span><span class="pln">m an animal</span><span class="pun">`);</span><span class="pln"> </span><span class="com">// أنا حيوان</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// يرث صنف الأرنب صنفَ الحيوان</span><span class="pln">
let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal</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">
    super</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="pun">};</span><span class="pln">

let plant </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">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"I'm a plant"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// أنا نبات</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// يرث صنف الشجرة صنفَ النبات</span><span class="pln">
let tree </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> plant</span><span class="pun">,</span><span class="pln">
  sayHi</span><span class="pun">:</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">sayHi </span><span class="com">// (*)</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

tree</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln">  </span><span class="com">// أنا حيوان (؟!؟)</span></pre>

<p>
	باستدعاء <code>tree.sayHi()‎</code> نرى الشجرة تقول ”أنا حيوان“. لا، لا! سبب ذلك بسيط جدًا:
</p>

<ul>
<li>
		في السطر <code>(*)</code> نسخنا التابِع <code>tree.sayHi</code> من <code>rabbit</code>. من يدري، ربّما لنقلّل من تكرار الشيفرات؟
	</li>
	<li>
		وخاصية <code>[[HomeObject]]</code> لها هي الصنف <code>rabbit</code>، إذ صنعنا التابِع داخل <code>rabbit</code>، وما من طريقة لتغيير <code>[[HomeObject]]</code>.
	</li>
	<li>
		نرى في شيفرة التابِع <code>tree.sayHi()‎</code> الاستدعاءَ <code>super.sayHi()‎</code>، وهو ينتقل إلى أعلى عند <code>rabbit</code> ويأخذ التابِع من <code>animal</code>.
	</li>
</ul>
<p>
	إليك صورة توضّح ما يحدث:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_06/super-homeobject-wrong.png.25aef1dadf226829ed9125b4e87fb982.png" data-fileid="45619" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="45619" data-unique="wmru23y2c" src="https://academy.hsoub.com/uploads/monthly_2020_06/super-homeobject-wrong.thumb.png.27dd2be49597fe6c84a68e2e1f717e6c.png" alt="super-homeobject-wrong.png"></a>
</p>

<h3>
	توابِع لا صفات داليّة
</h3>

<p>
	تُعرّف اللغة عن خاصيات <code>[[HomeObject]]</code> للتوابِع في الأصناف وفي الكائنات العادية. ولكن في حالة الكائنات فيجب تعريف التوابِع هكذا تمامًا <code>method()‎</code> وليس هكذا <code>"method: function()‎"</code>.
</p>

<p>
	قد لا نرى فرقًا جوهريًا في الطريقتين، لكنّ محرّكات جافاسكربت تراه كذلك.
</p>

<p>
	استعملنا في المثال أسفله صياغة ليست بتابِع للموازنة. بهذا لم تُضبط خاصية <code>[[HomeObject]]</code> ولن تعمل الوراثة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9404_6" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eat</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">// ‫نكتبها هكذا بدل eat()‎ عمدًا {...</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 rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal</span><span class="pun">,</span><span class="pln">
  eat</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">
    super</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

rabbit</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">();</span><span class="pln">  </span><span class="com">// Error calling super ‫(إذ [[HomeObject]] غير موجودة)</span></pre>

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

<ol>
<li>
		نستعمل <code>class Child extends Parent</code> لتوسعة الأصناف.

		<ul>
<li>
				أي أنّ خاصية <code>Child.prototype.__proto__‎</code> ستكون <code>Parent.prototype</code>، فتصير التوابِع موروثة.
			</li>
		</ul>
</li>
	<li>
		عندما نعيد تعريف الباني:
		<ul>
<li>
				علينا استدعاء الباني الأبّ باستعمال <code>super()‎</code> في الباني ”الابن“ ذلك قبل استعمال <code>this</code>.
			</li>
		</ul>
</li>
	<li>
		عندما نعيد تعريف أي تابع آخر:
		<ul>
<li>
				يمكننا استعمال <code>super.method()‎</code> في التابِع ”الابن“ لاستدعاء التابِع ”الأبّ“.
			</li>
		</ul>
</li>
	<li>
		أمور داخلية:
		<ul>
<li>
				تتذكّر التوابِع صنفها/كائنها وتحفظه في خاصية <code>[[HomeObject]]</code> الداخلية، هكذا يحلّ <code>super</code> التوابِع الأب.
			</li>
			<li>
				بذلك يكون ليس من الآمن نسخ تابِع لديه <code>super</code> من كائن ووضعه في آخر.
			</li>
		</ul>
</li>
</ol>
<p>
	كما وأنّ:
</p>

<ul>
<li>
		ليس للدوال السهمية لا <code>this</code> ولا <code>super</code>
	</li>
</ul>
<h2>
	تمارين
</h2>

<h3>
	خطأ في إنشاء سيرورة
</h3>

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

<p>
	إليك الشيفرة التي نُوسّع فيها صنف <code>Rabbit</code> من صنف <code>Animal</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9404_8" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

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

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

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">created </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// هنا</span><span class="pln">
let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"White Rabbit"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Error: this is not defined</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">rabbit</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span></pre>

<h4>
	الحل
</h4>

<p>
	هذا لأنّ على الباني الابن استدعاء <code>super()‎</code>.
</p>

<p>
	إليك الشيفرة الصحيحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9404_10" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

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

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

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Animal</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
    super</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="kwd">this</span><span class="pun">.</span><span class="pln">created </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">.</span><span class="pln">now</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"White Rabbit"</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">rabbit</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// White Rabbit</span></pre>

<h3>
	توسعة ساعة
</h3>

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

<p>
	لدينا صنف ساعة <code>Clock</code>، وهو حاليًا يطبع الوقت في كلّ ثانية.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9404_12" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Clock</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">({</span><span class="pln"> template </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">template </span><span class="pun">=</span><span class="pln"> template</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  render</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">

    let hours </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="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">hours </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> hours </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"> hours</span><span class="pun">;</span><span class="pln">

    let mins </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">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">mins </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> mins </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"> mins</span><span class="pun">;</span><span class="pln">

    let secs </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="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">secs </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> secs </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"> secs</span><span class="pun">;</span><span class="pln">

    let output </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">template
      </span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">'h'</span><span class="pun">,</span><span class="pln"> hours</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">'m'</span><span class="pun">,</span><span class="pln"> mins</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">'s'</span><span class="pun">,</span><span class="pln"> secs</span><span class="pun">);</span><span class="pln">

    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">output</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  stop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    clearInterval</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">timer</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  start</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">render</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">timer </span><span class="pun">=</span><span class="pln"> setInterval</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">render</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="pun">}</span></pre>

<p>
	أنشِئ الصنف الجديد <code>ExtendedClock</code> ليرث من <code>Clock</code> وأضِف المُعامل <code>precision</code>، وهو عدد الملّي ثانية <code>ms</code> بين كلّ ”تَكّة“. يجب أن يكون مبدئيًا <code>1000</code> (أي ثانية كاملة).
</p>

<ul>
<li>
		ضع شيفرتك في الملف <code>extended-clock.js</code>.
	</li>
	<li>
		تعديل ملف <code>clock.js</code> الأصلي ممنوع. وسّع الصنف.
	</li>
</ul>
<p>
	يمكن الاعتماد على <a href="https://plnkr.co/edit/3Ha7yGE4lnnhrgOq?p=preview" rel="external nofollow">هذه البيئة التجريبية</a> لحل التمرين.
</p>

<h4>
	الحل
</h4>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9404_14" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">ExtendedClock</span><span class="pln"> extends </span><span class="typ">Clock</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</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">
    super</span><span class="pun">(</span><span class="pln">options</span><span class="pun">);</span><span class="pln">
    let </span><span class="pun">{</span><span class="pln"> precision </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"> options</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">precision </span><span class="pun">=</span><span class="pln"> precision</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  start</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">render</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">timer </span><span class="pun">=</span><span class="pln"> setInterval</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(),</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">precision</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	<a href="https://plnkr.co/edit/CcPhRHTE11UljJq8?p=preview" rel="external nofollow">مشاهدة الحل في بيئة تجريبية</a>.
</p>

<h3>
	الأصناف تُوسّع الكائنات؟
</h3>

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

<p>
	كما نعلم فالكائنات كلها ترث <code>Object.prototype</code> وتقدر على الوصول إلى توابِع الكائنات ”العادية“ مثل <code>hasOwnProperty</code> وغيرها.
</p>

<p>
	مثال سريع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9404_16" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"Rab"</span><span class="pun">);</span><span class="pln">

</span><span class="com">// ‫التابِع hasOwnProperty مأخوذ من Object.prototype</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">hasOwnProperty</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">// true</span></pre>

<p>
	ولكن لو كتبنا ذلك جهارةً هكذا <code>"class Rabbit extends Object"</code> فالناتج يختلف عن <code>"class Rabbit"</code> فقط! غريب.
</p>

<p>
	تُراه ما الفرق؟
</p>

<p>
	إليك مثالًا عمّا أقصد (الشيفرة لا تعمل، لماذا؟ أصلِحها!):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9404_18" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Object</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"Rab"</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">hasOwnProperty</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">// true</span></pre>

<h4>
	الحل
</h4>

<p>
	أولًا نرى ما مشكلة الشيفرة تلك.
</p>

<p>
	متى شغّلنا الشيفرة بان سبب المشكلة: على باني الأصناف الموروثة استدعاء <code>super()‎</code> وإلّا تكون قيمة <code>"this"</code> ”غير معرّفة“.
</p>

<p>
	لذا سنصلحها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9404_20" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Object</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</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">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"Rab"</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">hasOwnProperty</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">// true</span></pre>

<p>
	ولكن… لم ننتهِ بعد.
</p>

<p>
	حتّى مع هذا … فهناك فرق مهم جوهري بين <code>"class Rabbit extends Object"</code> و<code>class Rabbit</code>.
</p>

<p>
	كما نعلم فصياغة <code>extends</code> تضبط كائنا prototype:
</p>

<ol>
<li>
		بين توابِع الباني لـِ<code>"prototype"</code> (بالنسبة للتوابع العادية).
	</li>
	<li>
		بين توابِع الباني نفسها (بالنسبة للتوابع الثابتة).
	</li>
</ol>
<p>
	في حالتنا إن <code>class Rabbit extends Object</code> تعني:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9404_22" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Object</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">);</span><span class="pln"> </span><span class="com">// (1) true</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Object</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// (2) true</span></pre>

<p>
	لذا يوفر <code>Rabbit</code> إمكانية الوصول إلى الدوال الثابتة للكائن <code>Object</code>. هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9404_24" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> extends </span><span class="typ">Object</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

</span><span class="pun">*!*</span><span class="pln">
</span><span class="com">// عادةً نستدعي ‫Object.getOwnPropertyNames</span><span class="pln">
alert </span><span class="pun">(</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">getOwnPropertyNames</span><span class="pun">({</span><span class="pln">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">2</span><span class="pun">}));</span><span class="pln"> </span><span class="com">// a,b</span><span class="pln">
</span><span class="pun">*/!*</span></pre>

<p>
	ولكن إذا لم يكن لدينا <code>extends Object</code> فلن تُسند <code>Rabbit.__proto__‎</code> للصنف <code>Object</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9404_26" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">);</span><span class="pln"> </span><span class="com">// (1) true</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Object</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// (2) false (!)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Function</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">);</span><span class="pln"> </span><span class="com">// as any function by default</span><span class="pln">

</span><span class="pun">*!*</span><span class="pln">
</span><span class="com">// error, no such function in Rabbit</span><span class="pln">
alert </span><span class="pun">(</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">getOwnPropertyNames</span><span class="pun">({</span><span class="pln">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">2</span><span class="pun">}));</span><span class="pln"> </span><span class="com">// Error</span><span class="pln">
</span><span class="pun">*/!*</span></pre>

<p>
	في هذه الحالة إن <code>Rabbit</code> لن يزودنا بطريقة للوصول إلى التوابع الثابتة في <code>Object</code>.
</p>

<p>
	بالمناسبة يملك النموذج الأولي للتوابع <code>Function.prototype</code> دوال مُعمَّمة مثل :<code>call</code> و <code>bind</code> ..إلخ. وهي متاحة دائمًا في كِلا الحالتين، لأن باني <code>Object</code> المضمن في اللغة هو <code>Object.__proto__ === Function.prototype</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_06/rabbit-extends-object.png.7ee20fc4fcc8aaed769a42695425a5b9.png" data-fileid="45614" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="45614" data-unique="qwmncnwyi" src="https://academy.hsoub.com/uploads/monthly_2020_06/rabbit-extends-object.thumb.png.199c75f994d961f8725c6723954d5b55.png" alt="rabbit-extends-object.png"></a>
</p>

<p>
	لذلك وباختصار هناك اختلافان وهما:
</p>

<table>
<thead><tr>
<th>
				class Rabbit
			</th>
			<th>
				class Rabbit extends Object
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				--
			</td>
			<td>
				يحتاج لاستدعاء<code>super()‎</code> في الباني
			</td>
		</tr>
<tr>
<td>
				<code>Rabbit.__proto__ === Function.prototype</code>
			</td>
			<td>
				<code>Rabbit.__proto__ === Object</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>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/class-inheritance" rel="external nofollow">Class inheritance</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">902</guid><pubDate>Wed, 10 Jun 2020 13:37:00 +0000</pubDate></item><item><title>&#x635;&#x64A;&#x627;&#x63A;&#x629; &#x627;&#x644;&#x623;&#x635;&#x646;&#x627;&#x641; &#x627;&#x644;&#x623;&#x633;&#x627;&#x633;&#x64A;&#x629; (Class basic syntax) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%B5%D9%8A%D8%A7%D8%BA%D8%A9-%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-class-basic-syntax-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r901/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_06/61.jpg.e5d0425f1cae7613a1d21b6ed3e96b85.jpg" /></p>

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

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

<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="">الباني والعامل "new" في جافاسكربت</a>"، يمكن للتعليمة <code>new function</code> القيام بهذه المهمة.
</p>

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

<h2>
	صياغة الأصناف <code>class</code>
</h2>

<p>
	إليك الصياغة الأساسية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">MyClass</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// توابِع الصنف</span><span class="pln">
  constructor</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">
  method1</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">
  method2</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">
  method3</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بعدها استعمل <code>new MyClass()‎</code> لتُنشِئ كائنًا جديدًا فيه التوابِع تلك.
</p>

<p>
	يُنادي الباني <code>constructor()‎</code> العبارة <code>new</code> تلقائيًا ليهيئ الكائن في المكان المطلوب.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_9" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

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

  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">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 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">
user</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span></pre>

<p>
	متى استدعينا <code>new User("John")‎</code>:
</p>

<ol>
<li>
		نكون أنشأنا كائنًا جديدًا.
	</li>
	<li>
		نكون شغّلنا (خلف الكواليس) الباني وممرًا له الوسطاء المناسبة، وإسناد هذه الوسطاء للمتغيرات المناسبة. هنا أُسندت الوسيط "John" إلى المتغير <code>name</code> عبر <code>this.name</code>.
	</li>
</ol>
<p>
	…وبعد ذلك، ننادي توابِع الكائن مثل <code>user.sayHi()‎</code>.
</p>

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

<h2>
	ما الصنف أصلًا؟
</h2>

<p>
	هذا جميل، ولكن ما هو الصنف <code>class</code> أساسًا؟ لو ظننته كيانًا جديدًا كليًا في اللغة، فأنت مخطئ.
</p>

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

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

<p>
	انظر بنفسك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_11" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  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">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">// الإثبات: الصنف‫ User هو دالّة</span><span class="pln">
alert</span><span class="pun">(</span><span class="kwd">typeof</span><span class="pln"> </span><span class="typ">User</span><span class="pun">);</span><span class="pln"> </span><span class="com">// function</span></pre>

<p>
	إليك ما يفعله الباني <code>class User {...}‎</code> حقًا:
</p>

<ol>
<li>
		يُنشِئ دالّة باسم <code>User</code> تصير هي ناتج التصريح عن الصنف، وتُؤخذ شيفرة الدالّة من الباني <code>constructor</code> (يُعامل الباني الصنف على أنّه فارغ إن لم تكن كتبت دالّة تغيّر ذلك).
	</li>
	<li>
		يُخزّن توابِع الصنف (مثل <code>sayHi</code>) في النموذج الأولي للكائن <code>User.prototype</code>.
	</li>
</ol>
<p>
	متى ما أُنشأ كائن جديد (<code>new User</code>)، واستدعينا تابِعًا منه يُؤخذ التابِع من كائن النموذج الأولي (prototype) كما وضّحنا في الفصل ”<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%B1%D8%A7%D8%AB%D8%A9-%D8%A7%D9%84%D9%86%D9%85%D9%88%D8%B0%D8%AC%D9%8A%D8%A9-prototypal-inheritance-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA%D8%8C-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-r888/" rel="">الوراثة النموذجية - 2 -</a>“. هكذا يكون للكائن تصريح الوصول إلى توابِع الصنف.
</p>

<p>
	يمكن أن نوضّح ناتج التصريح <code>class User</code> في هذه الصورة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_06/class-user.png.4b7feabf1991d2408f77bbec9bef37fc.png" data-fileid="45609" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="45609" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_06/class-user.thumb.png.75179083c85d27514f284ec4e9b1db72.png" alt="class-user.png"></a>
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_13" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  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">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">
alert</span><span class="pun">(</span><span class="kwd">typeof</span><span class="pln"> </span><span class="typ">User</span><span class="pun">);</span><span class="pln"> </span><span class="com">// function</span><span class="pln">

</span><span class="com">// ...أو للدّقة هو تابِع الباني</span><span class="pln">
alert</span><span class="pun">(</span><span class="typ">User</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">

</span><span class="com">// التوابِع موجودة في كائن النموذج الأولي ‫User.prototype، مثال:</span><span class="pln">
alert</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">);</span><span class="pln"> </span><span class="com">// alert(this.name);</span><span class="pln">

</span><span class="com">// في كائن النموذج الأولي ‫prototype تابِعين بالضبط</span><span class="pln">
alert</span><span class="pun">(</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getOwnPropertyNames</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">));</span><span class="pln"> </span><span class="com">// constructor, sayHi</span></pre>

<h2>
	ليست مجرد تجميل لغوي
</h2>

<p>
	يقول البعض بأنّ الأصناف <code>class</code> هي مجرد "تجميل لغوي" (Syntactic sugar)، أي أنّها صياغة أساس تصميمها هو تسهيل القراءة دون تقديم ما هو جديد، إذ يمكننا ببساطة التصريح عن ذات الشيء بدون تلك الكلمة المفتاحية <code>class</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_15" style="">
<span class="com">// نُعيد كتابة صنف المستخدم ‫User باستعمال الدوال فقط</span><span class="pln">

</span><span class="com">// ‫1. نُنشِئ دالّة الباني</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="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//عادةً إن أي نموذج أولي لتابِعٍ معين لديه باني</span><span class="pln">
</span><span class="com">// لذلك لسنا بحاجة لإنشائه</span><span class="pln">

</span><span class="com">// ‫2. نضيف التابع إلى النموذج الأولي</span><span class="pln">
</span><span class="typ">User</span><span class="pun">.</span><span class="pln">prototype</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="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">
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">
user</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span></pre>

<p>
	ناتج هذا التصريح أعلاه يشبه كثيرًا… لا بل يتطابق مع تصريح الصنف. لهذا ففكرة أنّ الأصناف هي حقًا تجميل لغوي لتعريف البواني مع توابِع كائن النموذج الأولي prototype لها - هي فكرة منطقية حقًا.
</p>

<p>
	مع ذلك، فهناك فوارق.
</p>

<ol>
<li>
		<p>
			أولًا، تُوضع على الدوال الّتي تُنشؤها عبارة <code>class</code> كخاصيّةً داخلية فريدة لهذا الصنف هكذا <code>‎[[FunctionKind]]:"classConstructor"‎</code>. لذا فالطريقتين (هذه وإنشائها يدويًا) ليستا تمامًا الشيء نفسه.
		</p>

		<p>
			وعلى عكس الدوالّ العادية، يلزم عليك استدعاء باني الصنف باستعمال <code>new</code>:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_17" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</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="kwd">typeof</span><span class="pln"> </span><span class="typ">User</span><span class="pun">);</span><span class="pln"> </span><span class="com">// function</span><span class="pln">
</span><span class="typ">User</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Error: Class constructor User cannot be invoked without 'new'</span></pre>

		<p>
			كما وأنّ تمثيل أغلب محرّكات جافاسكربت النصّيّ لباني الصنف يبدأ بالعبارة ”class…‎“
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_19" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</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="typ">User</span><span class="pun">);</span><span class="pln"> </span><span class="com">// class User { ... }</span></pre>

		<p>
			 
		</p>
	</li>
	<li>
		<p>
			توابِع الأصناف غير قابلة للإحصاء. يضبط التصريح عن الصنف راية <code>enumerable</code> على القيمة <code>false</code> لكلّ التوابِع في كائن النموذج الأولي للصنف <code>"prototype"</code>.
		</p>

		<p>
			هذا جميل إذ لا نريد ظهور توابِع الصنف حين نستعرضهن باستعمال حلقة <code>for..in</code>.
		</p>
	</li>
	<li>
		<p>
			تستعمل الأصناف الوضع الصارم دومًا. كلّ الشيفرة البرمجية في الباني تكون بالوضع الصارم (سبق وأن تحدثنا في <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%B6%D8%B9-%D8%A7%D9%84%D8%B5%D8%A7%D8%B1%D9%85-%D8%A7%D9%84%D9%86%D9%85%D8%B7-%D8%A7%D9%84%D8%AD%D8%AF%D9%8A%D8%AB-%D9%84%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%D8%A7%D8%AA-r670/" rel="">مقال سابق</a> عن الوضع الصارم في لغة جافاسكربت).
		</p>
	</li>
</ol>
<p>
	كما أنّ صياغة الأصناف تُفيدنا بكثير من المزايا نشرحها لاحقًا.
</p>

<h2>
	تعابير الأصناف
</h2>

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

<p>
	إليك مثال عن تعبير صنف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_21" style="">
<span class="pln">let </span><span class="typ">User</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">class</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">
    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>
	وكما تعابير الدوال المسمّاة (NFE) وهي اختصارًا لِـ (Named Function Expressions)، يمكن أن نضع اسمًا لتعابير الأصناف.
</p>

<p>
	ولو كان لتعبير الصنف اسمًا فسيكون ظاهرًا داخل الصنف فقط لا غير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_23" style="">
<span class="com">// ”تعبير أصناف مسمّى“ ‫(NCE)</span><span class="pln">
</span><span class="com">// ‫(ليس في المواصفات القياسية للغة هذا الاسم، لكنّها شبيهة بتعابير الدوال المسمّاة(NFE) )</span><span class="pln">
let </span><span class="typ">User</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">MyClass</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">
    alert</span><span class="pun">(</span><span class="typ">MyClass</span><span class="pun">);</span><span class="pln"> </span><span class="com">// لا يظهر اسم الصنف ‫MyClass إلّا داخل الصنف</span><span class="pln">
  </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">User</span><span class="pun">().</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// يعمل ويعرض تعريف ‫MyClass</span><span class="pln">

alert</span><span class="pun">(</span><span class="typ">MyClass</span><span class="pun">);</span><span class="pln"> </span><span class="com">// خطأ اسم تعبير الصنف ‫MyClass غير مرئي خارج الصنف</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_25" style="">
<span class="kwd">function</span><span class="pln"> makeClass</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">
  </span><span class="com">// declare a class and return it</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">class</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">
      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">
  </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 </span><span class="typ">User</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> makeClass</span><span class="pun">(</span><span class="str">"Hello"</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">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Hello</span></pre>

<h2>
	الجوالِب والضوابِط والاختصارات الأخرى
</h2>

<p>
	كما الكائنات المجردة فيمكن أن يكون في الأصناف ضوابِط وجوالِب (Gettes/Setters) وأسماءً محسوبةً للخاصيات (computed properties name) وغيرها.
</p>

<p>
	إليك مثالًا عن خاصية <code>user.name</code> كتبنا تنفيذها عبر ضابِط وجالِب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_27" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// يشغّل الضابِط</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// هنا</span><span class="pln">
  </span><span class="kwd">get</span><span class="pln"> name</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="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">
  </span><span class="kwd">set</span><span class="pln"> name</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">value</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&lt;</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">
      alert</span><span class="pun">(</span><span class="str">"Name is too short."</span><span class="pun">);</span><span class="pln"> </span><span class="com">// الاسم قصير جدًا</span><span class="pln">
      </span><span class="kwd">return</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"> 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">

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">
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><span class="pln">

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">""</span><span class="pun">);</span><span class="pln"> </span><span class="com">// الاسم قصير جدًا</span></pre>

<p>
	ينشئ التعريف عن الصنف جوالِب وضوابِط في كائن <code>User.prototype</code> هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_29" style="">
<span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperties</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">prototype</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="kwd">get</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="kwd">set</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="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	وهذا مثال عن استخدام أسماءً محسوبةً للخاصيّة (computed property name) داخل أقواس <code>[...]</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_31" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">User</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="str">'say'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'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="str">"Hello"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

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

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">User</span><span class="pun">().</span><span class="pln">sayHi</span><span class="pun">();</span></pre>

<h2>
	خاصيات الأصناف
</h2>

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

<p>
	نرى في المثال أعلاه بأنّ للصنف <code>User</code> توابِع فقط. هيًا نُضف الخاصية <code>name</code> للصنف <code>class User</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_33" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">User</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">"Anonymous"</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="pun">{</span><span class="pln">
    alert</span><span class="pun">(`</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}!`);</span><span class="pln">
  </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">User</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="typ">User</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫موجود في كائن User.prototype</span><span class="pln">
alert</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫undefined، غير موجودة في كائن User.prototype</span></pre>

<p>
	الأمر الجدير بالذكر أن خاصيات الصنف تعيّن على أنها كائنات فردية وليست ضمن النموذج الأولي للصنف <code>User.prototype</code>. من الناحية العملية تُعالجُ هذه الخاصيات بعد أن يُنهي الباني عمله.
</p>

<h3>
	إنشاء توابع مرتبطة بخاصيات الصنف
</h3>

<p>
	كما تحدثنا في فصلٍ سابق من هذه السلسلة <a href="https://academy.hsoub.com/programming/javascript/%D8%B1%D8%A8%D8%B7-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-function-binding-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r879/" rel="">ربط الدوالّ</a>، إن دلالات الكلمة المفتاحية <code>this</code> في الدوالّ ديناميكية إذ تعتمد إعتمادً أساسيًا على سياق الاستدعاء.
</p>

<p>
	لذا فإن مررها تابِعٌ من كائنٍ معين للكلمة المفتاحية <code>this</code>، واستدعيت مرة أخرى في مكان آخر بغير السياق السابق، فلن تشير إلى نفس الكائن السابق بسبب تغير سياق الاستدعاء.
</p>

<p>
	على سبيل المثال الشيفرة البرمجية التالية ستظهر <code>undefined</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_35" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</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">this</span><span class="pun">.</span><span class="pln">value </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">

  click</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">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">

let button </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Button</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

setTimeout</span><span class="pun">(</span><span class="pln">button</span><span class="pun">.</span><span class="pln">click</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">// undefined</span></pre>

<p>
	تدعى هذه المشكلة "ضياع قيمة this". وهنالك طريقتين لإصلاح هذه المشكلة كما ذكرنا في فصل "ربط الدوال"ّ
</p>

<ol>
<li>
		تمرير دالّة مغلّفة (مثل: <code>setTimeout(() =&gt; button.click(), 1000)</code>‎).
	</li>
	<li>
		ربط الدالّة بصنف كما في الباني التالي:
	</li>
</ol>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_37" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</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">this</span><span class="pun">.</span><span class="pln">value </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">click </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">click</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  click</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">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">

let button </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Button</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

setTimeout</span><span class="pun">(</span><span class="pln">button</span><span class="pun">.</span><span class="pln">click</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">// hello</span></pre>

<p>
	تزودنا خاصيات الصنف بصياغة مناسبة للحل الّذي سنستخدمه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_39" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</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">this</span><span class="pun">.</span><span class="pln">value </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">
  click </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</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">
</span><span class="pun">}</span><span class="pln">

let button </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Button</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

setTimeout</span><span class="pun">(</span><span class="pln">button</span><span class="pun">.</span><span class="pln">click</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">// hello</span></pre>

<p>
	‫<br>
	تنشئ الخاصية <code>click=‎ ()‎ =&gt;‎ {...}‎</code> دالّة مستقلة لكل كائن من <code>Button</code>، والكلمة المفتاحية <code>this</code> تشير إلى الكائن نفسه. وبإمكاننا بعدها تمرير <code>button.click</code> في أي مكان ومع احتفاظها بالقيمة الصحيحة للكلمة المفتاحية <code>this</code>.
</p>

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

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

<p>
	الصياغة الأساسية للأصناف هي كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_41" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">MyClass</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  prop </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">

  constructor</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><span class="pln">

  method</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">get</span><span class="pln"> something</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">set</span><span class="pln"> something</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="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="com">// تابِع اسمه محسوب (نضع رمزًا هنا)‫  </span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تقنيًا، فالصنف <code>MyClass</code> ما هو إلّا دالّة (تلك الّتي نكتبها لتكون الباني <code>constructor</code>)، بينما التوابِع والضوابِط والجوالِب تُكتب في كائن <code>MyClass.prototype</code>.
</p>

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

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

<h3>
	أعِد كتابتها لتكون صنفًا
</h3>

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

<p>
	كُتب صنف الساعة <code>Clock</code> وكأنّه دالّة. أعِد كتابته ليكون بصياغة الأصناف.
</p>

<p>
	ملاحظة: تدقّ عقارب الساعة في الطرفية، افتحها واحترس من العقارب اللادغة. اطلع على <a href="https://plnkr.co/edit/MmhvN3wn0sUBqjwR?p=preview&amp;preview" rel="external nofollow">تجربة حية</a> للتمرين.
</p>

<h4>
	الحل
</h4>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_187_43" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Clock</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">({</span><span class="pln"> template </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">template </span><span class="pun">=</span><span class="pln"> template</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  render</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">

    let hours </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="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">hours </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> hours </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"> hours</span><span class="pun">;</span><span class="pln">

    let mins </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">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">mins </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> mins </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"> mins</span><span class="pun">;</span><span class="pln">

    let secs </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="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">secs </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> secs </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"> secs</span><span class="pun">;</span><span class="pln">

    let output </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">template
      </span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">'h'</span><span class="pun">,</span><span class="pln"> hours</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">'m'</span><span class="pun">,</span><span class="pln"> mins</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">'s'</span><span class="pun">,</span><span class="pln"> secs</span><span class="pun">);</span><span class="pln">

    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">output</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  stop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    clearInterval</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">timer</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  start</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">render</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">timer </span><span class="pun">=</span><span class="pln"> setInterval</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">render</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="pun">}</span><span class="pln">


let clock </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Clock</span><span class="pun">({</span><span class="pln">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'h:m:s'</span><span class="pun">});</span><span class="pln">
clock</span><span class="pun">.</span><span class="pln">start</span><span class="pun">();</span></pre>

<p>
	ويمكن الاطلاع على <a href="https://plnkr.co/edit/4pMcC17UHDAvmsna?p=preview&amp;preview" rel="external nofollow">تجربة حية</a> للحل.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/class" rel="external nofollow">Class basic syntax</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript Language</a>
</p>
]]></description><guid isPermaLink="false">901</guid><pubDate>Mon, 08 Jun 2020 18:00:00 +0000</pubDate></item><item><title>&#x62A;&#x648;&#x627;&#x628;&#x639; &#x627;&#x644;&#x646;&#x645;&#x627;&#x630;&#x62C; &#x627;&#x644;&#x623;&#x648;&#x644;&#x64A;&#x629; &#x648;&#x627;&#x644;&#x643;&#x627;&#x626;&#x646;&#x627;&#x62A; &#x628;&#x644;&#x627; __proto__ &#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%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D8%A8%D9%84%D8%A7-__proto__-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r890/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_05/60.jpg.725123df3baaf81acaf2bdd0ce8ce9cd.jpg" /></p>

<p>
	في أوّل فصل من هذا القسم قُلنا بأنّ هناك طرائق حديثة لكتابة الخاصية [[prototype]].
</p>

<p>
	يُعدّ التابِع <code>__proto__</code> قديمًا وربّما نقول أيضًا لم يعد مستخدمًا (تحديدًا من جهة المتصفح في معايير جافاسكربت)
</p>

<p>
	النسخ الحديثة هي:
</p>

<ul>
<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/create" rel="external">Object.create(proto[, descriptors])‎</a> -- ينشئ كائنًا فارغًا بضبط <code>proto</code> الممرّر ليكون كائن <code>[[Prototype]]</code> مع واصِفات الخاصيات الاختيارية لو مُرّرت.
	</li>
	<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/getPrototypeOf" rel="external">Object.getPrototypeOf(obj)</a> -- يُعيد كائن <code>[[Prototype]]</code> للكائن <code>obj</code>.
	</li>
	<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/setPrototypeOf" rel="external">Object.setPrototypeOf(obj, proto)‎</a> -- يضبط الخاصية <code>[[Prototype]]</code> للكائن <code>obj</code> لتكون <code>proto</code>. ‎ هذه التعليمات يجب عليك استعمالها بدلًا من <code>__proto__</code>.
	</li>
</ul>
<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_7" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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">// نصنع كائنًا جديدًا يكون الكائن animal ككائنَ نموذج أولي له</span><span class="pln">
let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">animal</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">rabbit</span><span class="pun">.</span><span class="pln">eats</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="typ">Object</span><span class="pun">.</span><span class="pln">getPrototypeOf</span><span class="pun">(</span><span class="pln">rabbit</span><span class="pun">)</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> animal</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">

</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">setPrototypeOf</span><span class="pun">(</span><span class="pln">rabbit</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{});</span><span class="pln"> </span><span class="com">// نغيّر كائن النموذج الأولي للكائن ‫rabbit إلى {}</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_9" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">animal</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  jumps</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">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">rabbit</span><span class="pun">.</span><span class="pln">jumps</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	تنسيق الواصِفات هو نفس التنسيق الذي شرحناه في درس <a href="https://academy.hsoub.com/programming/javascript/%D8%B1%D8%A7%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%88%D9%88%D8%A7%D8%B5%D9%81%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-r881/" rel="">رايات الخاصيات وواصفاتها</a>.
</p>

<p>
	يمكننا أيضًا استعمال التابِع <code>Object.create</code> لنسخ الكائنات بتحكّم أكبر من نسخ الخاصيات في حلقة <code>for..in</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_11" style="">
<span class="com">// إنشاء نسخة مماثلة للكائن ‫obj</span><span class="pln">
let clone </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getPrototypeOf</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">),</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getOwnPropertyDescriptors</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">));</span></pre>

<p>
	يصنع هذا الاستدعاء نسخة حقيقية مطابقة عن <code>obj</code> بما فيها الخاصيات: قابلية العدّ و منع قابلية العدّ وخاصيات البيانات و الضوابط/الجوالب - ينسخ كلّ شيء مع خاصية <code>[[Prototype]]</code>.
</p>

<h2>
	لمحة تاريخية
</h2>

<p>
	لو عددنا الآن كلّ الطرائق التي نُدير فيها خاصية <code>[[Prototype]]</code> لوجدناها لا تُحصى! الكثير من الطرق لمهمة واحدة. ولكن لماذا؟
</p>

<p>
	طبعًا وكالعادة، لأسباب تاريخية.
</p>

<ul>
<li>
		بدأت الخاصية <code>"prototype"</code> للبواني (constructor) منذ زمن بعيد جدًا.
	</li>
	<li>
		ولاحقًا في 2012، ظهر التابِع <code>Object.create</code> في معيار اللغة. قدّم بذلك إمكانية صناعة الكائنات لها كائن نموذج أولي (prototype)، ولكن لم تقدّم أيّ طريقة لجلبه أو ضبطه. لهذا صنعت المتصفّحات تابع غير قياسي <code>__proto__</code> ليصل إلى كائن النموذج الأولي ويُتيح للمستخدم جلبه وضبطه متى أراد.
	</li>
	<li>
		بعدها في 2015 أُضيف التابِعين <code>Object.setPrototypeOf</code> و <code>Object.getPrototypeOf</code> إلى المعيار فيقوموا بنفس مقام التابع <code>__proto__</code>. ولكن بحكم الأمر الواقع، فقد كان <code>__proto__</code> موجودًا في كلّ مكان، وهكذا صار غير مستحسن استخدامه ونزل في المعيار إلى المُلحق باء (Annex B)، أي صار ”اختياريًا للبيئات التي ليست متصفّحات“.
	</li>
</ul>
<p>
	والآن صرنا نملك هذه الطرائق الثلاث نتنعّم بها.
</p>

<p>
	ولكن لماذا استبدلوا <code>__proto__</code> بالدوال <code>getPrototypeOf/setPrototypeOf</code>؟ سؤال مهم وعليه سنعرف ما السوء الكبير للتابِع <code>__proto__</code>. واصِل القراءة لمعرفة ذلك.
</p>

<p>
	<strong>ملاحظة</strong>:إن كانت السرعة عنصر مهم في مشروعك فلا تغيّر قيمة الخاصية <code>[[Prototype]]</code> للكائنات الحالية. عادة ما نُسند هذه الخاصية <code>[[Prototype]]</code> مرة واحدة فقط وذلك عند إنشاء الكائن ولا نعدلها بعد ذلك. ولكن بالطبع يمكننا استخدام الضابِط/الجالِب للخاصية <code>[[Prototype]]</code> في أي وقت نريده. الكائن <code>rabbit</code> يرث من الكائن <code>animal</code> ولن يتغير هذا الأمر لاحقًا.
</p>

<p>
	محرك لغة جافاسكربت محسّن على النحو الأمثل لهذا الغرض. إن عملية تغيير النموذج الأولي "على عجالة" باستخدام التابِع <code>Object.setPrototypeOf</code> أو التابِع <code>obj.__proto__=‎</code> تعدّ عملية بطيئة جدًا لأنها تكسر التحسينات الداخلية لعمليات الوصول إلى الخاصية لهذا الكائن. لذا فإن كانت السرعة تهمك أو كنت تعرف ما عواقب ما تُقدِم عليه فغيره، وإلا فلا.
</p>

<h2>
	الكائنات ”البسيطة جدًا“
</h2>

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

<p>
	ولكن… لو أردنا تخزين المفاتيح <em>التي يُعطينا إيّاها المستخدم</em> (مثل قاموس يكتبه المستخدم) فسنرى مشكلة ظريفة: كلّ المفاتيح تعمل عدا <code>"__proto__"</code>.
</p>

<p>
	انظر هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_13" style="">
<span class="pln">let obj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln">

let key </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"What's the key?"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"__proto__"</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">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"some value"</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]);</span><span class="pln"> </span><span class="com">// ‫ [object Object]، وليس ”some value“!</span></pre>

<p>
	لو كتب هنا المستخدم <code>__proto__</code>، فستُهمل عملية الإسناد! لا، هذا ليس مفاجئًا، إذ نعرف بأنّ <code>__proto__</code> مميّزة عن غيرها: فإمّا تكون كائنًا أو <code>null</code>. ممنوع أن تصير السلسلة النصية (String) كائنَ نموذج أولي. ولكن لم <em>تكن النية</em> أساسًا لتنفيذ هذا السلوك، صح؟ ما نريده هو تخزين أزواج المفاتيح والقيم، وهناك مفتاح اسمه <code>"__proto__"</code> لم يُحفظ كما المفترض، والّذي أنشأ مشكلة!
</p>

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

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

<p>
	ليست <code>__proto__</code> خاصية للكائن، بل خاصية وصول إلى <code>Object.prototype</code>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="44968" href="https://academy.hsoub.com/uploads/monthly_2020_05/object-prototype-2.png.1d0e5121637d706f77086eab49bb9d58.png" rel=""><img alt="object-prototype-2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="44968" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/object-prototype-2.thumb.png.a87ca600d97cbd83303ba6b7bd6f8b5b.png"></a>
</p>

<p>
	لذا لو قرأنا <code>obj.__proto__‎</code> أو ضبطناها، فسيُستدعى الجالِب (أو الضابِط) من كائن النموذج الأولي (prototype) لها وتجلب/تضبط كائن <code>[[Prototype]]</code>. فكما قلنا في بداية هذا القسم من الكتاب: ليست <code>__proto__</code> إلّا طريقة للوصول إلى الخاصية <code>[[Prototype]]</code> وليست الكائن نفسه.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_15" 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">create</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">);</span><span class="pln"> </span><span class="com">// هذه</span><span class="pln">

let key </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"What's the key?"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"__proto__"</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">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"some value"</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]);</span><span class="pln"> </span><span class="com">// "some value"</span></pre>

<p>
	ينشئ التابِع <code>Object.create(null)‎</code> كائنًا فارغًا ليس له نموذج أولي (prototype) (أي أنّ <code>[[Prototype]]</code> يساوي <code>null</code>):
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="44969" href="https://academy.hsoub.com/uploads/monthly_2020_05/object-prototype-null.png.58b246e6fb4d74ccc746cbeef81127ad.png" rel=""><img alt="object-prototype-null.png" class="ipsImage ipsImage_thumbnailed" data-fileid="44969" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/object-prototype-null.png.58b246e6fb4d74ccc746cbeef81127ad.png"></a>
</p>

<p>
	يعني أنْ ليس هناك أيّ جالِب أو ضابِط موروثان للخاصية <code>__proto__</code>، فهي الآن خاصية بيانات عادية وسيعمل مثالنا أعلاه كما نريد. نسمّي هذه الكائنات ”بالبسيطة جدًا“ (very plain) أو ”كائنات ليست إلّا قواميس“ إذ أنّها أبسط حتّى من الكائن البسيط (العادي) <code>{...}</code>. العيب هنا هو أنّ ليس فيها أيّ توابِع كائنات مضمّنة مثل <code>toString</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_17" 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">create</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">);</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">// Error (no toString)</span></pre>

<p>
	ولكن ربّما ذلك يكون كافيًا للمصفوفات المترابطة
</p>

<p>
	لاحظ كيف أنّ أغلب التوابِع المتعلّقة بالكائنات هي بالشكل <code>Object.something(...)</code> (مثل <code>Object.keys(obj)‎</code>) وليست موجودة في كائن النموذج الأولي (prototype)، وستعمل كما ينبغي لهذه الكائنات البسيطة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_19" style="">
<span class="pln">let arabicDictionary </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">);</span><span class="pln">
chineseDictionary</span><span class="pun">.</span><span class="pln">hello </span><span class="pun">=</span><span class="pln"> </span><span class="str">"hello"</span><span class="pun">;</span><span class="pln">
chineseDictionary</span><span class="pun">.</span><span class="pln">bye </span><span class="pun">=</span><span class="pln"> </span><span class="str">"bye"</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">(</span><span class="pln">arabicDictionary</span><span class="pun">));</span><span class="pln"> </span><span class="com">// hello,bye</span></pre>

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

<p>
	التوابِع الحديثة لضبط كائنات النماذج الأولية (prototype) والوصول إليها مباشرةً هي:
</p>

<ul>
<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/create" rel="external">Object.create(proto[, descriptors])</a>‎ -- ينشئ كائنًا فارغًا بضبط <code>proto</code> الممرّر ليكون كائن <code>[[Prototype]]</code> (يمكن أن يحمل القيمة <code>null</code>) مع واصِفات الخاصيات الاختيارية لو مُرّرت.
	</li>
	<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/getPrototypeOf" rel="external">Object.getPrototypeOf(obj)</a>‎ -- يُعيد كائن <code>[[Prototype]]</code> للكائن <code>obj</code> (مشابه لعمل الجالِب للخاصية <code>__proto__</code>).
	</li>
	<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/setPrototypeOf" rel="external">Object.setPrototypeOf(obj, proto)</a>‎ -- يضبط الخاصية <code>[[Prototype]]</code> للكائن <code>obj</code> لتكون <code>proto</code> (مشابه لعمل الضابِط للخاصية <code>__proto__</code>).
	</li>
</ul>
<p>
	ليس من الآمن استعمال الجالِب/الضابِط <code>__proto__</code> المضمّن في اللغة إن أردنا وضع مفاتيح صنعها المستخدم في الكائن. ليس ذلك آمنًا إذ يمكن أن يُدخل المستخدم <code>"__proto__"</code> مفتاحًا وسنواجه خطأً له عواقب محالة التنبّؤ نأمل أن يُحمد عقباها.
</p>

<p>
	لذا يمكننا إمّا استعمال التابِع <code>Object.create(null)</code>‎ لإنشاء كائن ”بسيط جدًا“ بدون استعمال <code>__proto__</code> أو يمكننا استغلال كائنات الخرائط <code>Map</code> وهو الأفضل. كما يمكننا أيضًا نسخ الكائنات مع جميع واصفاتِها من خلال التابع <code>Object.create</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_23" style="">
<span class="pln">let clone </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getPrototypeOf</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">),</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getOwnPropertyDescriptors</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">));</span></pre>

<p>
	كما أنّا وضّحنا كيف أنّ <code>__proto__</code> ليس إلّا جالِبًا/ضابِطًا للخاصية <code>[[Prototype]]</code> وهو موجود تحت ظلّ <code>Object.prototype</code> مثل غيره من التوابِع.
</p>

<p>
	يمكننا إنشاء كائن ليس له نموذج أولي (prototype) باستعمال <code>Object.create(null)‎</code>، وهكذا نستعملها على أنّها ”خرائط خام (Map)“، والجميل أنّها لا تُمانع قيمة مثل <code>"__proto__"</code> لتكون مفتاحًا فيها.
</p>

<p>
	توابِع أخرى:
</p>

<ul>
<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/keys" rel="external">Object.keys(obj)</a> / <a href="https://wiki.hsoub.com/JavaScript/Object/values" rel="external">Object.values(obj)</a> / <a href="https://wiki.hsoub.com/JavaScript/Object/entries" rel="external">Object.entries(obj)</a>‎ -- تعيد مصفوفة فيها جميع السلاسل (مفعلٌ بها خاصية قابلية العدّ) على شكل أسماء/قيم/أزواج مفاتيح-قيم.
	</li>
	<li>
		<a href="mdn:js/Object/getOwnPropertySymbols" rel="">Object.getOwnPropertySymbols(obj)</a>‎ -- تُعيد مصفوفةً فيها جميع الخاصيات الرمزية (symbol properties) الموجودة مباشرةً في الكائن المعطي.
	</li>
	<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/getOwnPropertyNames" rel="external">Object.getOwnPropertyNames(obj)</a>‎ -- تُعيد مصفوفةً فيها جميع الخاصيات التابعة مباشرةً للكائن المعطي، بما في ذلك الخاصيات غير القابلة للإحصاء (non-enumerable) لكن باستثناء خاصيات الرموز <code><a href="https://wiki.hsoub.com/JavaScript/Symbol" rel="external">Symbol</a></code>.
	</li>
	<li>
		<a href="mdn:js/Reflect/ownKeys" rel="">Reflect.ownKeys(obj)</a>‎ -- تعيد مصفوفة من جميع المفاتيح الخاصة بها.
	</li>
	<li>
		<a href="https://wiki.hsoub.com/JavaScript/Object/hasOwnProperty" rel="external">obj.hasOwnProperty(key)</a>‎: تعيد <code>true</code> لو كان للكائن <code>obj</code> خاصيةً ما مباشرةً (أي أنها لم يرثها).
	</li>
</ul>
<p>
	تُعيد كلّ التوابِع التي تُعيد خاصيات الكائن (مثل <code>Object.keys</code> وغيرها) خاصياتها ”هي“. لو أردنا تلك الموروثة فعلينا استعمال حلقة <code>for..in</code>.
</p>

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

<h3>
	إضافة <code>toString</code> إلى <code>dictionary</code>
</h3>

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

<p>
	لديك الكائن <code>dictionary</code> حيث أنشأناه باستعمال <code>Object.create(null)‎</code> ليخزّن أزواج <code>key/value</code> أيًا كانت.
</p>

<p>
	أضِف التابِع <code>dictionary.toString()‎</code> فيه ليُعيد قائمة الخاصيات مفصولة بفواصل. يجب ألا يظهر التابِع <code>toString</code> في حلقة <code>for..in</code> عند مرورها على الكائن.
</p>

<p>
	إليك طريقة عمل التابِع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_26" style="">
<span class="pln">let dictionary </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">);</span><span class="pln">

</span><span class="com">// اكتب هنا الشيفرة التي تُضيف تابِع ‫dictionary.toString</span><span class="pln">

</span><span class="com">// نُضيف بعض البيانات</span><span class="pln">
dictionary</span><span class="pun">.</span><span class="pln">apple </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Apple"</span><span class="pun">;</span><span class="pln">
dictionary</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">=</span><span class="pln"> </span><span class="str">"test"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ليس ‫__proto__ هنا إلّا خاصية لا أكثر</span><span class="pln">

</span><span class="com">// في الحلقة ‫apple و __proto__ فقط</span><span class="pln">
</span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let key in dictionary</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">key</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫"apple"، ثمّ "__proto__"</span><span class="pln">
</span><span class="pun">}</span><span class="pln">  

</span><span class="com">// حان دور التابِع toString الذي كتبته</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">dictionary</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "apple,__proto__"</span></pre>

<h4>
	الحل
</h4>

<p>
	يمكن أن يأخذ التابِع كلّ الخاصيات (keys) القابلة للإحصاء باستعمال <code>Object.keys</code> ويطبع قائمة بها.
</p>

<p>
	لنمنع التابِع <code>toString</code> من قابلية الإحصاء لنُعرّفه باستعمال واصِف خاصيات. تُتيح لنا صياغة التابِع <code>Object.create</code> تقديم الكائن مع واصِفات الخاصيات كوسيط ثاني يمرر للتابِع.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_30" style="">
<span class="com">// الشيفرة</span><span class="pln">
let dictionary </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="kwd">null</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="com">// نعرّف الخاصية ‫toString</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="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="kwd">this</span><span class="pun">).</span><span class="pln">join</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">

dictionary</span><span class="pun">.</span><span class="pln">apple </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Apple"</span><span class="pun">;</span><span class="pln">
dictionary</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">=</span><span class="pln"> </span><span class="str">"test"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// في الحلقة apple و __proto__ </span><span class="pln">
</span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let key in dictionary</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">key</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫"apple"، ثمّ "__proto__"</span><span class="pln">
</span><span class="pun">}</span><span class="pln">  

</span><span class="com">// قائمة من الخاصيات طبعها ‫toString مفصولة بفواصل</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">dictionary</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "apple,__proto__"</span></pre>

<p>
	متى أنشأنا الخاصية باستعمال واصِف فستكون راياتها بقيمة <code>false</code> مبدئيًا. إذًا في الشيفرة أعلاه التابِع <code>dictionary.toString</code> ليس قابلًا للإحصاء.
</p>

<p>
	ألقِ نظرة على درس "<a href="https://academy.hsoub.com/programming/javascript/%D8%B1%D8%A7%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%88%D9%88%D8%A7%D8%B5%D9%81%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-r881/" rel="">رايات الخاصيات وواصِفاتها</a>" لتُنعش ذاكرتك.
</p>

<h3>
	الفرق بين الاستدعاءات
</h3>

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

<p>
	لنُنشئ ثانيةً كائن <code>rabbit</code> جديد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_32" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype</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="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">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"Rabbit"</span><span class="pun">);</span></pre>

<p>
	هل تؤدّي هذه الاستدعاءات نفس المهمة أم لا؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_34" style="">
<span class="pln">rabbit</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln">
</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getPrototypeOf</span><span class="pun">(</span><span class="pln">rabbit</span><span class="pun">).</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln">
rabbit</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span></pre>

<h4>
	الحل
</h4>

<p>
	في الاستدعاء الأول يكون <code>this == rabbit</code>، بينما في البقية يكون <code>this</code> مساويًا إلى <code>Rabbit.prototype</code> إذ أنّ الكائن الفعلي يكون قبل النقطة.
</p>

<p>
	إذًا فالاستدعاء الأول هو الوحيد الذي يعرض <code>Rabbit</code>، بينما البقية تعرض <code>undefined</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6381_36" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype</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="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">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"Rabbit"</span><span class="pun">);</span><span class="pln">

rabbit</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln">                        </span><span class="com">// Rabbit</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln">              </span><span class="com">// undefined</span><span class="pln">
</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getPrototypeOf</span><span class="pun">(</span><span class="pln">rabbit</span><span class="pun">).</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// undefined</span><span class="pln">
rabbit</span><span class="pun">.</span><span class="pln">__proto__</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>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/prototype-methods" rel="external nofollow">Prototype methods, objects without __proto__</a>‎ من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">890</guid><pubDate>Mon, 25 May 2020 09:13:45 +0000</pubDate></item><item><title>&#x627;&#x644;&#x646;&#x645;&#x627;&#x630;&#x62C; &#x627;&#x644;&#x623;&#x648;&#x644;&#x64A;&#x629; &#x627;&#x644;&#x623;&#x635;&#x64A;&#x644;&#x629; (Native prototypes) &#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%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%A3%D8%B5%D9%8A%D9%84%D8%A9-native-prototypes-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r889/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_05/59.jpg.60bbe5329b241b305ab85b69fcee253e.jpg" /></p>

<p>
	كثيرٌ من الكائنات تستعمل الخاصية <code>"prototype"</code>، حتّى في محرّك جافاسكربت، إذ تستعملها كلّ البواني المضمّنة في اللغة.
</p>

<p>
	لنرى أولًا تفاصيلها وبعدها كيفية استعمالها لإضافة مزايا جديدة إلى الكائنات المضمّنة.
</p>

<h2>
	Object.prototype
</h2>

<p>
	لنقل بأنّا طبعنا كائنًا فارغًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2308_6" style="">
<span class="pln">let 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"> obj </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "[object Object]" ?</span></pre>

<p>
	ما هذه الشيفرة الّتي ولّدت النصّ <code>"[object Object]"</code>؟ هذه أفعال تابِع <code>toString</code> المضمّن في اللغة، ولكن أين هذا التابِع فكائن <code>obj</code> فارغ!
</p>

<p>
	ولكن لو فكّرنا لحظة… فالاختصار هذا <code>obj = {}‎</code> هو كأنما كتبنا <code>obj = new Object()‎</code>، وهنا <code>Object</code> هو الباني المضمّن في اللغة يُشير الخاصية prototype في الكائن إلى كائن آخر ضخم فيه التابِع <code>toString</code> وغيره من توابِع.
</p>

<p>
	هذا ما يحدث:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/object-prototype.png.3eacd0957fd9726c870c646c1e5f462d.png" data-fileid="44952" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44952" data-unique="tzsf3ipad" src="https://academy.hsoub.com/uploads/monthly_2020_05/object-prototype.thumb.png.fea7d907b62fcacc24b68a62d71efe38.png" alt="object-prototype.png"></a>
</p>

<p>
	متى استدعينا <code>new Object()‎</code> (أو أنشأنا كائن مجرّد <code>{...}</code>)، ضُبطت الخاصية <code>[[Prototype]]</code> لذاك الكائن إلى <code>Object.prototype</code> طبقًا للقاعدة الّتي تحدّثنا عنها في الفصل السابق:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/object-prototype-1.png.5c75035f6149106499ebd244f11b6364.png" data-fileid="44951" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44951" data-unique="38mu6kll6" src="https://academy.hsoub.com/uploads/monthly_2020_05/object-prototype-1.thumb.png.bfa432ba4e453a4b1c0633ea497f4dec.png" alt="object-prototype-1.png"></a>
</p>

<p>
	لذا متى حدث استدعاء إلى <code>obj.toString()‎</code> أخذت لغة جافاسكربت التابِعَ من <code>Object.prototype</code>.
</p>

<p>
	يمكننا التأكّد من هذا هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2308_8" style="">
<span class="pln">let 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">obj</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">
</span><span class="com">// obj.toString === obj.__proto__.toString == Object.prototype.toString</span></pre>

<p>
	لاحظ أنّ لم تعد هناك كائنات <code>[[Prototype]]</code> في السلسلة فوق <code>Object.prototype</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2308_10" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">);</span><span class="pln"> </span><span class="com">// null</span></pre>

<h2>
	كائنات النماذج الأولية الأخرى المضمّنة في اللغة
</h2>

<p>
	الكائنات الأخرى مثل المصفوفات <code>Array</code> والتواريخ <code>Date</code> والدوال <code>Function</code> تضع هي الأخرى توابِعها في كائنات النماذج الأولية prototype.
</p>

<p>
	فمثلًا، حين نُنشئ المصفوفة <code>[1, 2, 3]</code> تستدعي لغة جافاسكربت داخليًا الباني <code>new Array()‎</code> بنفسها، بذلك يصير كائن <code>Array.prototype</code> كائنَ النموذج الأولي (prototype) ويقدّم له التوابِع اللازمة. هذا الأمر يزيد من كفاءة الذاكرة.
</p>

<p>
	بحسب المواصفات القياسية للغة، أنّ لكلّ كائنات النماذج الأولية (prototype) المضمّنة كائنَ <code>Object.prototype</code> آخر فوقها، ولهذا يقول الناس بأنّ ”كلّ شيء يرث الكائنات (Objects)“.
</p>

<p>
	إليك صورة تصف هذا كله
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/native-prototypes-classes.png.a280f41cdbb461b4a0f39b7b8f7054cd.png" data-fileid="44950" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44950" data-unique="f9fs0mbgr" src="https://academy.hsoub.com/uploads/monthly_2020_05/native-prototypes-classes.thumb.png.feab67c72a7471d662674221f84de4b0.png" alt="native-prototypes-classes.png"></a>
</p>

<p>
	لنرى أمر كائنات النماذج الأولية prototype يدويًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2308_12" style="">
<span class="pln">js runlet 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="com">// هل ترث ‫Array.prototype؟</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true </span><span class="pln">

</span><span class="com">// ثمّ من ‫Object.prototype؟</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true </span><span class="pln">

</span><span class="com">// وفوق هذا كلّه ‫null.</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">);</span><span class="pln"> </span><span class="com">// null</span></pre>

<p>
	أحيانًا تتداخل التوابِع في كائنات النماذج الأولية (prototype) مع بعضها. فمثلًا للكائن <code>Array.prototype</code> تابِعًا خاصًا فيه <code>toString</code> يعرض العناصر بينها فاصلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2308_14" 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 &lt;-- ناتج Array.prototype.toString</span></pre>

<p>
	كما رأينا سابقًا فللكائن <code>Object.prototype</code> تابِع <code>toString</code> أيضًا، ولكنّ <code>Array.prototype</code> أقرب في سلسلة وراثة النموذج الأولي prototype وبذلك تستعمل لغة جافاسكربت تابِع المصفوفة لا الكائن.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/native-prototypes-array-tostring.png.c4a10514e0deffde60e535d7b51c0974.png" data-fileid="44949" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44949" data-unique="39xmcrwny" src="https://academy.hsoub.com/uploads/monthly_2020_05/native-prototypes-array-tostring.thumb.png.6fb749734bef83fd7071bed8253bbd91.png" alt="native-prototypes-array-tostring.png"></a>
</p>

<p>
	كما أنّ الأدوات في المتصفّحات (مثل طرفية كروم للمطوّرين) تعرض الوراثة (إن التعليمة <code>console.dir</code> ربّما سنحتاجها للكائنات المضمنة في اللغة).
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="44948" data-unique="obscegt9o" src="https://academy.hsoub.com/uploads/monthly_2020_05/console_dir_array.png.14300e7dfdedb1257443a2906bfee8cf.png" alt="console_dir_array.png"></p>

<p>
	كما أنّ الكائنات الأخرى المضمّنة في اللغة تعمل بنفس الطريقة. حتى الدوالّ هم كائنات مبنية من خلال البواني المخصصة للدوالّ والمضمّنة في اللغة والدوالّ الخاصة بها (مثل الاستدعاء(<code>call</code>)/التطبيق(<code>apply</code>) وغيرهم من الدوالّ) مأخوذة من النموذج الأولي للدوالّ <code>Function.prototype</code>. ولديهم دالّة <code>toString</code> أيضًا.
</p>

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

alert</span><span class="pun">(</span><span class="pln">f</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">==</span><span class="pln"> </span><span class="typ">Function</span><span class="pun">.</span><span class="pln">prototype</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">f</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">==</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true، إذ ترث الكائنات</span></pre>

<h2>
	الأنواع الأولية
</h2>

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

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

<p>
	نرى هذه الكائنات مؤقّتًا إذ تُصنع سريعًا دون معرفتنا
</p>

<p>
	إن القيم <code>null</code> و <code>undefined</code> لا تملك أي كائنٍ مغلّف لها، وليس لديها أي دوال ولا خاصيات ولا حتى نماذج أولية.
</p>

<h2>
	تغيير كائنات النماذج الأولية الأصيلة
</h2>

<p>
	يمكن تعديل كائنات النماذج الأولية الأصيلة. فمثلًا يمكننا إضافة تابِع إلى <code>String.prototype</code> فيصبح متاحًا لكلّ السلاسل النصية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2308_18" style="">
<span class="typ">String</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">show </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="str">"BOOM!"</span><span class="pun">.</span><span class="pln">show</span><span class="pun">();</span><span class="pln"> </span><span class="com">// BOOM!</span></pre>

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

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

<p>
	لهذا تعدّ عملية تعديل كائنات النماذج الأولية الأصيلة على أنّها فكرة سيئة.
</p>

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

<p>
	ترقيع نقص الدعم (أو Polyfilling) هو صناعة بديل عن تابِع توضّحه مواصفة جافاسكربت ولكنّه ليس مدعومًا في محرّك جافاسكربت الهدف.
</p>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2308_20" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="typ">String</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">repeat</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">// نُضيفه إلى كائن ‫prototype</span><span class="pln">

  </span><span class="typ">String</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">repeat </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</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">// نكرّر السلسلة النصية ‫n مرّة</span><span class="pln">

    </span><span class="com">// في الواقع فالشيفرة الممتازة هي أكثر تعقيدًا من هذه</span><span class="pln">
    </span><span class="com">// (تجد خوارزميتها الكاملة في المواصفة)</span><span class="pln">
    </span><span class="com">// ولكن حتى التعويض الناقص يكون كافيًا أحيانًا كثيرة</span><span class="pln">
    </span><span class="kwd">return</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">n </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">).</span><span class="pln">join</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">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"La"</span><span class="pun">.</span><span class="pln">repeat</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">// LaLaLa</span></pre>

<h2>
	الاستعارة من كائنات النماذج الأولية
</h2>

<p>
	تحدّثنا في الفصل "<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D8%B2%D8%AE%D8%B1%D9%81%D8%A7%D8%AA-decorators-%D9%88%D8%A7%D9%84%D8%AA%D9%85%D8%B1%D9%8A%D8%B1-forwarding-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r878/" rel="">المُزخرِفات والتمرير، التابِعان call وapply</a>"، عن استعارة التوابِع، أي حين نأخذ تابِعًا من كائن وننسخه إلى كائن غيره.
</p>

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

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

obj</span><span class="pun">.</span><span class="pln">join </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">join</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"> obj</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">// Hello,world!</span></pre>

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

<p>
	يمكننا أيضًا الوراثة بضبط <code>obj.__proto__‎</code> على <code>Array.prototype</code> فتصير توابِع المصفوفات <code>Array</code> مُتاحة للكائن <code>obj</code> تلقائيًا.
</p>

<p>
	ولكن ما إن يرث <code>obj</code> من أيّ كائن آخر (غير كائن <code>Array.prototype</code>) يصير هذا مستحيلًا. لا تنسَ بأنّا لا نستطيع الوراثة إلا من كائن واحد فقط لا غير.
</p>

<p>
	تُعدّ هذه الميزة (ميزة استعارة التوابِع) ميزةً مرنة إذ تتيح لنا دمج مختلف مزايا الكائنات إن احتجناها.
</p>

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

<ul>
<li>
		تتبع كافة الكائنات المضمّنة في اللغة هذا النمط:
		<ul>
<li>
				التوابِع مخزّنة داخل كائن النموذج الأولي (مثل <code>Array.prototype</code> و <code>Object.prototype</code> و<code>Date.prototype</code> وغيرها)
			</li>
			<li>
				لا يخزّن الكائن إلّا بياناته (مثل عناصر المصفوفة وخصائص الكائن والتاريخ)
			</li>
		</ul>
</li>
	<li>
		تخزّن الأنواع الأولية أيضًا توابِعها في كائنات النماذج الأولية لكائنات تغليف: <code>Number.prototype</code> و <code>String.prototype</code> و <code>Boolean.prototype</code>. فقط <code>undefined</code> و <code>null</code> ليس لهما كائنات تغليف.
	</li>
	<li>
		يمكنك تعديل كائنات النماذج الأولية المضمّنة في اللغة أو إضافة توابِع جديدة لها، ولكنّ تغييرها ليس أمرًا مستحسنًا. ربما تكون إضافة المعايير الجديدة (والّتي لا يدعمها محرّك جافاسكربت بعد) هي الحالة الوحيدة المسموح بها.
	</li>
</ul>
<h2>
	تمارين
</h2>

<h2>
	إضافة التابع f.defer(ms)‎ إلى الدوال
</h2>

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

<p>
	أضِف إلى كائن النموذج الأولي المخصص للدوال التابِعَ <code>defer(ms)‎</code>، ووظيفته تشغيل الدالة بعد <code>ms</code> مِلّي ثانية.
</p>

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

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

f</span><span class="pun">.</span><span class="pln">defer</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">);</span><span class="pln"> </span><span class="com">// تعرض ‫”Hello!“ بعد ثانية واحدة</span></pre>

<h4>
	الحل
</h4>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2308_26" style="">
<span class="typ">Function</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">defer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</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">
  setTimeout</span><span class="pun">(</span><span class="kwd">this</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="kwd">function</span><span class="pln"> f</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">

f</span><span class="pun">.</span><span class="pln">defer</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">);</span><span class="pln"> </span><span class="com">// تعرض ‫”Hello!“ بعد ثانية واحدة</span></pre>

<h3>
	إضافة المُزخرِف defer()‎ إلى الدوال
</h3>

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

<p>
	أضِف إلى كائن النموذج الأولي المخصص للدوالّ التابِعَ <code>defer(ms)‎</code>، ووظيفته إعادة غلاف يُؤخّر الاستدعاء <code>ms</code> مِلّي ثانية.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2308_28" style="">
<span class="kwd">function</span><span class="pln"> f</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"> b </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">defer</span><span class="pun">(</span><span class="lit">1000</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">// يعرض ”3“ بعد ثانية واحدة</span></pre>

<p>
	لاحِظ أنّ عليك تمرير الوُسطاء إلى الدالة الأصل.
</p>

<h4>
	الحل
</h4>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2308_30" style="">
<span class="typ">Function</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">defer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</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">
  let f </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">function</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">
    setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> args</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="pun">};</span><span class="pln">

</span><span class="com">// نتأكّد</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> f</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"> b </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">defer</span><span class="pun">(</span><span class="lit">1000</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">// يعرض ”3“ بعد ثانية واحدة</span></pre>

<p>
	لاحظ بأنّا استعملنا <code>this</code> في التابِع <code>f.apply</code> لجعل المزخرف يعمل لكائن الدوالّ
</p>

<p>
	لذا فإن استدعيَ تابع التغليف كدالّة كائن عندها ستمرر <code>this</code> إلى الدالة الأصلية <code>f</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2308_32" style="">
<span class="typ">Function</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">defer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</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">
  let f </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">function</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">
    setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> args</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="pun">};</span><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">
  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">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"> user</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">.</span><span class="pln">defer</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">);</span><span class="pln">

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

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/native-prototypes" rel="external nofollow">Native prototypes</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">889</guid><pubDate>Mon, 25 May 2020 08:22:32 +0000</pubDate></item><item><title>&#x627;&#x644;&#x648;&#x631;&#x627;&#x62B;&#x629; &#x627;&#x644;&#x646;&#x645;&#x648;&#x630;&#x62C;&#x64A;&#x629; (Prototypal inheritance) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;&#x60C; &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x62B;&#x627;&#x646;&#x64A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%B1%D8%A7%D8%AB%D8%A9-%D8%A7%D9%84%D9%86%D9%85%D9%88%D8%B0%D8%AC%D9%8A%D8%A9-prototypal-inheritance-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA%D8%8C-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-r888/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_05/58.jpg.2b67dea77626aa841d4aa804b5e7e93a.jpg" /></p>

<p>
	سنكمل في هذا الدرس الحديث عن موضوع الوراثة النموذجية الذي بدأناه في <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%B1%D8%A7%D8%AB%D8%A9-%D8%A7%D9%84%D9%86%D9%85%D9%88%D8%B0%D8%AC%D9%8A%D8%A9-prototypal-inheritance-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA%D8%8C-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r887/" rel="">الدرس السابق</a>.
</p>

<p>
	لا تنسَ بأنّك يمكنك إنشاء كائنات جديدة من خلال دالّة الباني (مثل <code>new F()‎ ‫</code>). لو كان <code>F.prototype</code> كائن جافاسكربت، فإن المعامِل <code>new</code> سيضبط الخاصية <code>[[Prototype]]</code> لهذا الكائن الجديد.
</p>

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

<p>
	لاحظ بأنّ <code>F.prototype</code> هنا تعني وجود خاصية عادية باسم <code>"prototype"</code> للكائن <code>F</code>. ربما تفكّر وكأنها النموذج الأولي لهذا الكائن، ولكن لا… فهنا نعني حرفيًا أنها خاصية عادية لها هذا الاسم.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_6" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">=</span><span class="pln"> animal</span><span class="pun">;</span><span class="pln"> </span><span class="com">// هنا</span><span class="pln">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"White Rabbit"</span><span class="pun">);</span><span class="pln"> </span><span class="com">//  rabbit.__proto__ == animal</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">eats </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	تعني التعليمة <code>Rabbit.prototype = animal</code> حرفيًا الآتي: "ما إن يُنشأ كائن <code>new Rabbit</code>، أسنِد خاصية <code>[[Prototype]]</code> له لتكون للكائن <code>animal</code>".
</p>

<p>
	إليك الصورة الناتجة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="44944" href="https://academy.hsoub.com/uploads/monthly_2020_05/proto-constructor-animal-rabbit.png.da1943ce57ae3b622093c3ed74442385.png" rel=""><img alt="proto-constructor-animal-rabbit.png" class="ipsImage ipsImage_thumbnailed" data-fileid="44944" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/proto-constructor-animal-rabbit.thumb.png.d2ed52f13d2ebfe01621cab1884d66fd.png"></a>
</p>

<p>
	في الصورة نرى <code>"prototype"</code> في سهم أفقي (أي أنّها خاصية عادية) بينما <code>[[Prototype]]</code> في سهم رأسي (أي أنّها توضّح وراثة كائن <code>rabbit</code> للكائن <code>animal</code>).
</p>

<p>
	إن الخاصية <code>F.prototype</code> تستخدم عند الإنشاء فقط أي عندما تستدعى تعليمة <code>new F</code> وتُسند للكائن القيمة المناسبة للخاصية <code>[[Prototype]]</code>. في حال تغيرت الخاصية <code>F.prototype</code> مثلًا (<code>F.prototype = &lt;another object&gt;‎</code>)، عندها ستحصل الكائنات المنشأة بعد هذا التغيير على القيمة الجديدة للخاصية <code>[[Prototype]]</code> (أي الكائن الجديد)، ولكن الكائنات القديمة مازالت تحتفظ بالقيمة القديمة.
</p>

<h2>
	القيمة الإفتراضية للخاصية prototype في الباني
</h2>

<p>
	لكلّ دالة خاصية <code>"prototype"</code> حتّى لو لم نقدّمها نحن.
</p>

<p>
	إن القيمة الإفتراضية للخاصية <code>"prototype"</code> تُشير إلى نفس الدالّة.
</p>

<p>
	هكذا تمامًا:
</p>

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

</span><span class="com">/* كائن‫ prototype
Rabbit.prototype = { constructor: Rabbit };
*/</span></pre>

<p>
	 
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="44943" href="https://academy.hsoub.com/uploads/monthly_2020_05/function-prototype-constructor.png.c70e772636364b724c82e3e68c51b5e6.png" rel=""><img alt="function-prototype-constructor.png" class="ipsImage ipsImage_thumbnailed" data-fileid="44943" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/function-prototype-constructor.thumb.png.f842b6c0980dd4d3dff087e15c351784.png"></a>
</p>

<p>
	يمكننا فحص ذلك أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_10" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</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">// Rabbit.prototype = { constructor: Rabbit }</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">constructor </span><span class="pun">==</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	طبيعيًا، إن لم نعدل أي شيء، ستكون خاصية <code>constructor</code> مُتاحة لكلّ كائنات <code>rabbit</code> من خلال كائن <code>[[Prototype]]</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_12" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</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">// Rabbit.prototype = { constructor: Rabbit }</span><span class="pln">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ترث من‫ {constructor: Rabbit}</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">rabbit</span><span class="pun">.</span><span class="pln">constructor </span><span class="pun">==</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫ true من prototype‎ </span></pre>

<p>
	 
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="44945" href="https://academy.hsoub.com/uploads/monthly_2020_05/rabbit-prototype-constructor.png.556f53c67d9f53ab088b49ad22a0853e.png" rel=""><img alt="rabbit-prototype-constructor.png" class="ipsImage ipsImage_thumbnailed" data-fileid="44945" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/rabbit-prototype-constructor.thumb.png.56f3f708c9182eb5c2bc64373743d7f7.png"></a>
</p>

<p>
	يمكننا استعمال الخاصية <code>constructor</code> لإنشاء كائن جديد باستعمال نفس الباني الّذي أنشأ الكائن الموجود حاليًا.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_14" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</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">
  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">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">(</span><span class="str">"White Rabbit"</span><span class="pun">);</span><span class="pln">

</span><span class="com">// انظر</span><span class="pln">
let rabbit2 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">(</span><span class="str">"Black Rabbit"</span><span class="pun">);</span></pre>

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

<p>
	ولكن الأمر الأهم الّذي يتعلّق بِـ <code>"constructor"</code> هو أنّ <strong>لغة جافاسكربت نفسها لا تتأكّد من صحّة قيمة خاصية <code>"constructor"</code>.</strong>
</p>

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

<p>
	فمثلًا لو أردنا استبدال القيمة الإفتراضية للخاصية prototype، فلن يملك الكائن أيّ خاصية <code>"constructor"</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_16" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  jumps</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">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Rabbit</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">rabbit</span><span class="pun">.</span><span class="pln">constructor </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">);</span><span class="pln"> </span><span class="com">// false</span></pre>

<p>
	ولهذا لنُبقي على خاصية <code>"constructor"</code> الصحيحة يمكننا إضافة الخاصيات وإزالتها من كائن <code>"prototype"</code> الإفتراضي بدل الطريقة السابقة. هكذا:
</p>

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

</span><span class="com">// بدل الكتابة على كلّ ‫Rabbit.prototype</span><span class="pln">
</span><span class="com">// نُضيف ما نريد إليه</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">jumps </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
</span><span class="com">// هكذا تبقى خاصية‫ Rabbit.prototype.constructor الإفتراضية محفوظة</span></pre>

<p>
	أو يمكننا (لو أردنا) إعادة إنشاء الخاصية <code>constructor</code> يدويًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_20" style="">
<span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  jumps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  constructor</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Rabbit</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></pre>

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

<p>
	شرحنا في هذا الفصل سريعًا طريقة ضبط كائن <code>[[Prototype]]</code> للكائنات الّتي أنشأتها بدالّة الباني. سنرى لاحقًا أنماط متقدّمة في البرمجة تعتمد على هذا الطريقة.
</p>

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

<ul>
<li>
		تضبط الخاصية <code>F.prototype</code> (لا تظنّها كائن <code>[[Prototype]]</code>) لكائنٍ ما الخاصية <code>[[Prototype]]</code> لكلّ الكائنات الجديدة متى استدعيت <code>new F()‎</code>.
	</li>
	<li>
		يجب أن تكون قيمة <code>F.prototype</code> إمّا كائنًا أو <code>null</code>، ولن تعمل أيّة قيم أخرى.
	</li>
	<li>
		هذا التأثير للخاصية <code>"prototype"</code> موجود فقط حين يُضبط في دالة الباني وحين يُنفّذ بتعليمة <code>new</code>.
	</li>
</ul>
<p>
	في الكائنات العادية ليست بخاصية خاصة جدًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_22" 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">
  prototype</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Bla-bla"</span><span class="pln"> </span><span class="com">// نزعنا السحر</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	لكلّ الدوالّ مبدئيًا <code>F.prototype = { constructor: F }‎</code>، فيمكننا أن نأخذ باني معين من كائن ما بالدخول إلى الخاصية <code>"constructor"</code> الخاصة به.
</p>

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

<h3>
	تغيير الخاصية ”prototype“
</h3>

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

<p>
	أنشأنا في الشيفرة أدناه كائنًا جديدًا <code>new Rabbit</code> وحاولنا بعدها تعديل الخاصية prototype لهذا الكائن.
</p>

<p>
	بادئ ذي بدء، كانت الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_24" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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">

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

alert</span><span class="pun">(</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">eats </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<ol>
<li>
		<p>
			وأضفنا سلسلة نصية أخرى (عليها علامة). ماذا سيعرض التابِع <code>alert</code>؟
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_26" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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">

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

</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype </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"> rabbit</span><span class="pun">.</span><span class="pln">eats </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ?</span></pre>

		<p>
			 
		</p>
	</li>
	<li>
		<p>
			وماذا لو… كانت الشيفرة كهذه (استبدلنا سطرًا فيها)؟
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_28" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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">

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

</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">eats </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">

alert</span><span class="pun">(</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">eats </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ?</span></pre>

		<p>
			 
		</p>
	</li>
	<li>
		<p>
			وماذا عن هذه (استبدلنا سطرًا أيضًا)؟
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_30" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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">

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

</span><span class="kwd">delete</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">eats</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"> rabbit</span><span class="pun">.</span><span class="pln">eats </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ?</span></pre>

		<p>
			 
		</p>
	</li>
	<li>
		<p>
			وهذه… أيضًا:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_32" style="">
<span class="kwd">function</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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">

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

</span><span class="kwd">delete</span><span class="pln"> </span><span class="typ">Rabbit</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">eats</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"> rabbit</span><span class="pun">.</span><span class="pln">eats </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ?</span></pre>

		<p>
			 
		</p>
	</li>
</ol>
<h4>
	الحل
</h4>

<p>
	الإجابات:
</p>

<ol>
<li>
		<p>
			<code>true</code>.
		</p>

		<p>
			عملية الإسناد على <code>Rabbit.prototype</code> تضع الخاصية <code>[[Prototype]]</code> للكائنات الجديدة، ولكنّها لا تعدّل على الكائنات الموجودة مسبقًا.
		</p>
	</li>
	<li>
		<p>
			<code>false</code>. عملية الإسناد تكون من خلال الخاصية <code>Rabbit.prototype</code>، إن الخاصية المشار إليها هنا <code>Rabbit.prototype</code> ليست مكررًا، وإنما بقيت يُشار إليها من خلال <code>Rabbit.prototype</code> و الخاصية <code>[[Prototype]]</code> للكائن <code>rabbit</code>.
		</p>

		<p>
			لذا حين نغيّر المحتوى في الطريقة الأولى سنرى النتائج في الطريقة الثانية.
		</p>
	</li>
	<li>
		<p>
			<code>true</code>. كلّ عمليات الحذف تطبق مباشرة على الكائن. تحاول هذه التعليمة <code>delete rabbit.eats</code> حذف الخاصية المخصصة للكائن <code>rabbit</code> ولكنها ليست لها. لذا العملية لن يكون لها أي تأثير.
		</p>
	</li>
	<li>
		<p>
			<code>undefined</code>.
		</p>

		<p>
			حُذفت الخاصية <code>eats</code> من كائن prototype وما عادت موجودة بعد الآن.
		</p>
	</li>
</ol>
<h3>
	إنشاء كائن جديد من خلال نفس باني لكائنٍ آخر
</h3>

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

<p>
	تخيّل بأنّ لدينا الكائن الفريد <code>obj</code> وأنشأته بدالة الباني، ولكننا… لا نعرف أيّ دالة هذه، ولكن مع ذلك نريد استعمال نفس الباني لإنشاء كائن جديد آخر.
</p>

<p>
	أيمكن لهذه الشيفرة إنجاز المهمة؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_34" style="">
<span class="pln">let obj2 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">();</span></pre>

<p>
	اكتب مثالين باستخدام بانيين للكائن <code>obj</code>، واحدًا يعمل مع الشيفرة أعلاه، وواحدًا لا يعمل له.
</p>

<h4>
	الحل
</h4>

<p>
	يمكن أن نستعمل هذه الطريقة لو كنّا متأكدين مئة بالمئة بأنّ خاصية <code>"constructor"</code> تحمل القيمة الصحيحة.
</p>

<p>
	فمثلًا لو لم نعدّل على <code>"prototype"</code> المبدئية فستعمل هذه الشيفرة بلا ريب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_36" 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="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">
let user2 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">(</span><span class="str">'Pete'</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> user2</span><span class="pun">.</span><span class="pln">name </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Pete (عملت!)</span></pre>

<p>
	نفذت الشيفرة تنفيذًا صحيحًا إذ أنّ <code>User.prototype.constructor == User</code>.
</p>

<p>
	ولكن… لو أتى أحدهم مثلًا وكتب على <code>User.prototype</code> ونسي إعادة إنشاء <code>constructor</code> لتُشير إلى كائن المستخدم <code>User</code>، فلن تعمل الشيفرة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6716_38" 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="pun">}</span><span class="pln">
</span><span class="typ">User</span><span class="pun">.</span><span class="pln">prototype </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 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">
let user2 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">(</span><span class="str">'Pete'</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> user2</span><span class="pun">.</span><span class="pln">name </span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined</span></pre>

<p>
	لمَ قيمة <code>user2.name</code> هي <code>undefined</code>؟
</p>

<p>
	إليك طريقة عمل تعليمة <code>new user.constructor('Pete')‎</code>:
</p>

<ol>
<li>
		أولًا، تبحث عن المُنشِئ <code>constructor</code> داخل <code>user</code>، ولا تجده.
	</li>
	<li>
		ثمّ تتبع سلسلة prototype وتجد prototype الكائن <code>user</code> هو <code>User.prototype</code>، وأيضًا لا تجده.
	</li>
	<li>
		قيمة <code>User.prototype</code> ما هي إلّا كائنًا فارغًا <code>{}</code>، و قيمة الخاصية prototype لهذا الكائن هي <code>Object.prototype</code>، وهنا وجدنا <code>Object.prototype.constructor == Object</code> بذلك استعملناه.
	</li>
</ol>
<p>
	وفي نهاية الأمر، لدينا التعليمة <code>let user2 = new Object('Pete')‎</code> إذ أنّ الباني الخاص بالكائن <code>Object</code> يتجاهل الوسطاء وينشىء دائمًا كائنًا فارغًا. بطريقة مشابهة جدًا للتعليمة <code>let user2 = {}‎</code> والّتي أنشأت لنا الكائن <code>user2</code> في نهاية الأمر.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/function-prototype" rel="external nofollow">F.prototype</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">888</guid><pubDate>Mon, 25 May 2020 07:45:54 +0000</pubDate></item><item><title>&#x627;&#x644;&#x648;&#x631;&#x627;&#x62B;&#x629; &#x627;&#x644;&#x646;&#x645;&#x648;&#x630;&#x62C;&#x64A;&#x629; (Prototypal inheritance) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;&#x60C; &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x623;&#x648;&#x644;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%B1%D8%A7%D8%AB%D8%A9-%D8%A7%D9%84%D9%86%D9%85%D9%88%D8%B0%D8%AC%D9%8A%D8%A9-prototypal-inheritance-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA%D8%8C-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r887/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_05/57.jpg.5b149637a6c0c227d3af58b451954a6a.jpg" /></p>

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

<p>
	فمثلًا لدينا كائن مستخدم <code>user</code> له خاصيات وتوابِع، وأردنا إنشاء نسخ عنه (مدراء <code>admin</code> وضيوف <code>guest</code>) لكن معدّلة قليلًا. سيكون رائعًا لو أعدنا استعمال الموجود في كائن المستخدم بدل نسخه أو إعادة كتابة توابِعه، سيكون رائعًا لو صنعنا كائنًا جديدًا فوق كائن <code>user</code>.
</p>

<p>
	<em>الوراثة النموذجية</em> (تدعى أيضًا الوراثة عبر كائن النموذج الأولي prototype)* هي الميزة الّتي تساعدنا في تحقيق هذا الأمر.
</p>

<h2>
	الخاصية [[Prototype]]
</h2>

<p>
	لكائنات جافاسكربت خاصية مخفية أخرى باسم <code>[[Prototype]]</code> (هذا اسمها في المواصفات القياسية للغة جافاسكربت)، وهي إمّا أن تكون <code>null</code> أو أن تشير إلى كائن آخر. نسمّي هذا الكائن بِـ”prototype“ (نموذج أولي).
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/object-prototype-empty.png.11ddd7b206fe665696ba549be978732c.png" data-fileid="44932" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44932" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/object-prototype-empty.png.11ddd7b206fe665696ba549be978732c.png" alt="object-prototype-empty.png"></a>
</p>

<p>
	إن كائن النموذج الأولي ”سحريٌ“ إن صحّ القول، فحين نريد قراءة خاصية من كائن <code>object</code> ولا يجدها محرّك جافاسكربت، يأخذها تلقائيًا من كائن النموذج الأولي لذاك الكائن. يُسمّى هذا في علم البرمجة ”بالوراثة النموذجية“ (‏Prototypal inheritance)، وهناك العديد من المزايا الرائعة في اللغة وفي التقنيات البرمجية مبنية عليها.
</p>

<p>
	الخاصية <code>[[Prototype]]</code> هي خاصية داخلية ومخفية، إلّا أنّ هناك طُرق عديدة لنراها. ‎<br>
	إحداها استعمال <code>__proto__</code> هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_7" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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">
let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  jumps</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">

rabbit</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">=</span><span class="pln"> animal</span><span class="pun">;</span><span class="pln"> </span><span class="com">// هنا</span></pre>

<p>
	<strong><code>__proto__</code> هو الجالب والضابط القديم للخاصية <code>[[Prototype]]</code></strong> كانت تستخدم قديمًا، ولكن في اللغة الحديثة استبدلت بالدالتين <code>Object.getPrototypeOf/Object.setPrototypeOf</code> وهي أيضًا تعمل عمل الجالب والضابط للنموذج الأولي (سندرس هذه الدوالّ لاحقًا في هذا الدرس).
</p>

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

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

<p>
	مثال على ذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_9" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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">
let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  jumps</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">

rabbit</span><span class="pun">.</span><span class="pln">__proto__ </span><span class="pun">=</span><span class="pln"> animal</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"> rabbit</span><span class="pun">.</span><span class="pln">eats </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"> rabbit</span><span class="pun">.</span><span class="pln">jumps </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	هنا نضبط (في السطر <code>(*)</code>) كائن <code>animal</code> ليكون النموذج الأولي (Prototype) للكائن <code>rabbit</code>.
</p>

<p>
	بعدها متى ما حاولت التعليمة <code>alert</code> قراءة الخاصية <code>rabbit.eats</code> (انظر <code>(**)</code>)، ولم يجدها في كائن <code>rabbit</code> ستتبع لغة جافاسكربت الخاصية <code>[[Prototype]]</code> لمعرفة ما هو كائن النموذج الأولي لكائن <code>rabbit</code>، وسيجده كائن <code>animal</code> (البحث من أسفل إلى أعلى):
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/proto-animal-rabbit.png.960391a0dd75a3ac08e6ec60bf6975d9.png" data-fileid="44937" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44937" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/proto-animal-rabbit.png.960391a0dd75a3ac08e6ec60bf6975d9.png" alt="proto-animal-rabbit.png"></a>
</p>

<p>
	يمكن أن نقول هنا بأنّ الكائن <code>animal</code> هو النموذج الأولي للكائن <code>rabbit</code>، أو كائن <code>rabbit</code> هو نسخة نموذجية من الكائن <code>animal</code>.
</p>

<p>
	وبهذا لو كان للكائن <code>animal</code> خاصيات وتوابِع كثيرة مفيدة، تصير مباشرةً موجودة عند كائن <code>rabbit</code>. نسمّي هذه الخاصيات بأنّها ”موروثة“.
</p>

<p>
	لو كان للكائن <code>animal</code> تابِعًا فيمكننا استدعائه في كائن <code>rabbit</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_11" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  walk</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">"Animal walk"</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 rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  jumps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// نأخذ ‫ walk من كائن النموذج الأولي</span><span class="pln">
rabbit</span><span class="pun">.</span><span class="pln">walk</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Animal walk</span></pre>

<p>
	يُؤخذ التابِع تلقائيًا من كائن النموذج الأولي، هكذا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/proto-animal-rabbit-walk.png.dcae5df0d25e77289172d9137db1f465.png" data-fileid="44936" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44936" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/proto-animal-rabbit-walk.png.dcae5df0d25e77289172d9137db1f465.png" alt="proto-animal-rabbit-walk.png"></a>
</p>

<p>
	يمكن أيضًا أن تكون سلسلة الوراثة النموذجية (النموذج الأولي) أطول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_13" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  walk</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">"Animal walk"</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 rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  jumps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal </span><span class="com">// (*)</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let longEar </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  earLength</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> rabbit </span><span class="com">// (*)</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// نأخذ الدالّة ‫walk من سلسلة الوراثة النموذجية</span><span class="pln">
longEar</span><span class="pun">.</span><span class="pln">walk</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Animal walk</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">longEar</span><span class="pun">.</span><span class="pln">jumps</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true (من rabbit)</span></pre>

<p>
	 
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/proto-animal-rabbit-chain.png.28c5d674f5ee1d0b0dd6c59fb6101b6b.png" data-fileid="44933" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44933" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/proto-animal-rabbit-chain.thumb.png.9c35fa21c125cda5ca9720711efd6da5.png" alt="proto-animal-rabbit-chain.png"></a>
</p>

<p>
	ولكن، هناك مُحددان للوراثة النموذجية وهما:
</p>

<ol>
<li>
		لا يمكن أن تكون سلسلة الوراثة النموذجية دائرية (على شكل حلقة). ما إن تُسند <code>__proto__</code> بطريقة دائرية فسترمي لغة جافاسكربت خطأً.
	</li>
	<li>
		يمكن أن تكون قيمة <code>__proto__</code> إمّا كائنًا أو <code>null</code>، وتتجاهل لغة جافاسكربت الأنواع الأخرى.
	</li>
</ol>
<p>
	ومن الواضح جليًا أيضًا أي كائن سيرث كائن <code>[[Prototype]]</code> واحد وواحد فقط، لا يمكن للكائن وراثة كائنين.
</p>

<h2>
	كائن النموذج الأولي للقراءة فقط
</h2>

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

<p>
	في المثال أسفله نُسند التابِع <code>walk</code> إلى الكائن <code>rabbit</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_15" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  walk</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">/* لن يستعمل الكائن‫ `rabbit` هذا التابِع */</span><span class="pln">  
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal
</span><span class="pun">};</span><span class="pln">

rabbit</span><span class="pun">.</span><span class="pln">walk </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">"Rabbit! Bounce-bounce!"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

rabbit</span><span class="pun">.</span><span class="pln">walk</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Rabbit! Bounce-bounce!</span></pre>

<p>
	من الآن فصاعدًا فستجد استدعاء التابع <code>rabbit.walk()‎</code> سيكون من داخل كائن <code>rabbit</code> مباشرةً وتُنفّذه دون استعمال كائن النموذج الأولي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/proto-animal-rabbit-walk-2.png.78d0b039c552f4a17cdd8dbeec97343a.png" data-fileid="44934" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44934" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/proto-animal-rabbit-walk-2.png.78d0b039c552f4a17cdd8dbeec97343a.png" alt="proto-animal-rabbit-walk-2.png"></a>
</p>

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

<p>
	لهذا السبب نرى الخاصية <code>admin.fullName</code> في الشيفرة أسفله تعمل كما ينبغي لها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_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">
  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="kwd">set</span><span class="pln"> fullName</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="kwd">this</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">surname</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">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="kwd">get</span><span class="pln"> fullName</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="kwd">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="kwd">this</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">

let admin </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</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="kwd">true</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">admin</span><span class="pun">.</span><span class="pln">fullName</span><span class="pun">);</span><span class="pln"> </span><span class="com">// John Smith (*)</span><span class="pln">

</span><span class="com">// عمل الضابِط!</span><span class="pln">
admin</span><span class="pun">.</span><span class="pln">fullName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Alice Cooper"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// (**)</span></pre>

<p>
	هنا في السطر <code>(*)</code> نرى أن <code>admin.fullName</code> استدعت الجالِب داخل الكائن <code>user</code>، ولهذا استُدعيت الخاصية. وفي السطر <code>(**)</code> نرى عملية إسناد للخاصية <code>admin.fullName</code> ولهذا استدعيَ الضابِط داخل الكائن <code>user</code>.
</p>

<h2>
	ماذا عن "this"؟
</h2>

<p>
	بعدما تتمعّن في المثال أعلاه، يمكن أن تتساءل ما قيمة <code>this</code> داخل <code>set fullName(value)‎</code>؟ أين كُتبت القيم الجديدة <code>this.name</code> و <code>this.surname</code>؟ داخل الكائن <code>user</code> أم داخل الكائن <code>admin</code>؟
</p>

<p>
	جواب هذا السؤال المحيّر بسيط: لا تؤثّر كائنات النموذج الأولي على قيمة <code>this</code>.
</p>

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

<p>
	لهذا فالضابِط الّذي يستدعي <code>admin.fullName=‎</code> يستعمل كائن <code>admin</code> عوضًا عن <code>this</code> وليس الكائن <code>user</code>.
</p>

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

<p>
	فمثلًا هنا، يمثّل كائن <code>animal</code> ”مخزّنَ توابِع“ وكائن <code>rabbit</code> يستغلّ هذا المخزن.
</p>

<p>
	فاستدعاء <code>rabbit.sleep()‎</code> يضبط <code>this.isSleeping</code> على كائن <code>rabbit</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_19" style="">
<span class="com">// للحيوان توابِع</span><span class="pln">
let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  walk</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">isSleeping</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 walk</span><span class="pun">`);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  sleep</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">isSleeping </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let rabbit </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">"White Rabbit"</span><span class="pun">,</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// يعدّل rabbit.isSleeping</span><span class="pln">
rabbit</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">();</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">rabbit</span><span class="pun">.</span><span class="pln">isSleeping</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">animal</span><span class="pun">.</span><span class="pln">isSleeping</span><span class="pun">);</span><span class="pln"> </span><span class="com">// غير معرّف (لا يوجد خاصية معرفة في كائن النموذج الأولي بهذا الأسم)‫ </span></pre>

<p>
	الصورة الناتجة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/proto-animal-rabbit-walk-3.png.003a400d8ed07e69d2aa02618bdc0e4d.png" data-fileid="44935" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44935" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/proto-animal-rabbit-walk-3.png.003a400d8ed07e69d2aa02618bdc0e4d.png" alt="proto-animal-rabbit-walk-3.png"></a>
</p>

<p>
	لو كانت هناك كائنات أخرى (مثل الطيور <code>bird</code> والأفاعي <code>snake</code> وغيرها) ترث الكائن<code>animal</code>، فسيمكنها الوصول إلى توابِع الكائن <code>animal</code>، إلّا أنّ قيمة <code>this</code> في كلّ استدعاء للتوابِع سيكون على الكائن الّذي استُدعيت منه، وستعرِفه لغة جافاسكربت أثناء الاستدعاء (أي سيكون الكائن الّذي قبل النقطة) ولن يكون <code>animal</code>. لذا متى كتبنا البيانات من خلال <code>this</code>، فستُخزّن في تلك الكائنات الّتي استدعيت عليها <code>this</code>.
</p>

<p>
	وبهذا نخلص إلى أنّ التوابِع مشتركة، ولكن حالة الكائن ليست مشتركة.
</p>

<h2>
	حلقة for..in
</h2>

<p>
	كما أنّ حلقة <code>for..in</code> تَمرُّ على الخاصيات الموروثة هي الأخرى.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_21" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  jumps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// يُعيد التابع ‫Object.keys خصائص الكائن نفسه فقط</span><span class="pln">
alert</span><span class="pun">(</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">(</span><span class="pln">rabbit</span><span class="pun">));</span><span class="pln"> </span><span class="com">// jumps</span><span class="pln">

</span><span class="pun">*!*</span><span class="pln">
</span><span class="com">// تدور حلقة‫ for..in على خصائص الكائن نفسه والخصائص الموروثة معًا</span><span class="pln">
</span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let prop in rabbit</span><span class="pun">)</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln">prop</span><span class="pun">);</span><span class="pln"> </span><span class="com">// jumps ثمّ eats</span><span class="pln">
</span><span class="pun">*/!*</span></pre>

<p>
	لو لم تكن هذه النتيجة ما نريد (أي نريد استثناء الخاصيات الموروثة)، فيمكن استعمال التابِع <a href="https://wiki.hsoub.com/JavaScript/Object/hasOwnProperty" rel="external">obj.hasOwnProperty(key)</a> المضمّن في اللغة: إذ يُعيد <code>true</code> لو كان للكائن <code>obj</code> نفسه (وليس للموروث منه) خاصية بالاسم <code>key</code>.
</p>

<p>
	بهذا يمكننا ترشيح الخاصيات الموروثة (ونتعامل معها على حدة):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_23" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eats</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">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  jumps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let prop in rabbit</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let isOwn </span><span class="pun">=</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">hasOwnProperty</span><span class="pun">(</span><span class="pln">prop</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isOwn</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(`</span><span class="typ">Our</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">prop</span><span class="pun">}`);</span><span class="pln"> </span><span class="com">// تخصّنا:‫ jumps</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">
    alert</span><span class="pun">(`</span><span class="typ">Inherited</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">prop</span><span class="pun">}`);</span><span class="pln"> </span><span class="com">// ورثناها: ‫eats</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هنا نرى سلسلة الوراثة الآتية: يرث كائن <code>rabbit</code> كائنَ <code>animal</code>، والّذي يرثه هكذا <code>Object.prototype</code> (إذ أنّه كائن مجرّد <code>{...}</code>، وهذا السلوك المبدئي)، وبعدها يرث <code>null</code>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/rabbit-animal-object.png.0e730a3078940770376b08b702ac2a0d.png" data-fileid="44938" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44938" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/rabbit-animal-object.thumb.png.f1170c225e5ead5df344353b32c7699e.png" alt="rabbit-animal-object.png"></a>
</p>

<p>
	ملاحظة لطيفة في هذا السياق وهي: من أين أتى التابِع <code>rabbit.hasOwnProperty</code>؟ لم نعرّفه يدويًا! لو تتبّعناه في السلسلة لرأينا بأنّ كائن النموذج الأولي <code>Object.prototype.hasOwnProperty</code> هو من قدّم التابِع، أي بعبارة أخرى، ورث كائن <code>rabbit</code> هذا التابِع من كائن النموذج الأولي.
</p>

<p>
	ولكن لحظة… لماذا لم يظهر تابع <code>hasOwnProperty</code> في حلقة <code>for..in</code> كما ظهرت <code>eats</code> و <code>jumps</code> طالما تُظهر حلقات <code>for..in</code> الخاصيات الموروثة؟
</p>

<p>
	الإجابة هنا بسيطة أيضًا: لإنه مُنع من قابلية العدّ (من خلال إسناده لقيمة الراية <code>enumerable:false</code>). في النهاية هي مِثل غيرها من الخاصيات في <code>Object.prototype</code>- تملك الراية <code>enumerable:false</code>، وحلقة <code>for..in</code> لا تمرّ إلّا على الخاصيات القابلة للعدّ. لهذا السبب لم نراها لا هي ولا خاصيات <code>Object.prototype</code> الأخرى.
</p>

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

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

<ul>
<li>
		لكلّ كائنات جافاسكربت خاصية <code>[[Prototype]]</code> مخفية قيمتها إمّا أحد الكائنات أو <code>null</code>.
	</li>
	<li>
		يمكننا استعمال <code>obj.__proto__‎</code> للوصول إلى هذه الخاصية (وهي خاصية جالِب/ضابِطة). هناك طرق أخرى سنراها لاحقًا.
	</li>
	<li>
		الكائن الّذي تُشير إليه الخاصية <code>[[Prototype]]</code> يسمّى كائن النموذج الأولي.
	</li>
	<li>
		لو أردنا قراءة خاصية داخل كائن ما <code>obj</code> أو استدعاء تابِع، ولم تكن موجودة/يكن موجودًا، فسيحاول محرّك جافاسكربت البحث عنه/عنها في كائن النموذج الأولي.
	</li>
	<li>
		عمليات الكتابة والحذف تتطبّق مباشرة على الكائن المُستدعي ولا تستعمل كائن النموذج الأولي (إذ يعدّ أنّها خاصية بيانات وليست ضابِطًا).
	</li>
	<li>
		لو استدعينا التابِع <code>‎obj.method()‎‏</code> وأخذ المحرّك التابِع <code>method</code> من كائن النموذج الأولي، فلن تتغير إشارة <code>this</code> وسيُشير إلى <code>obj</code>، أي أنّ التوابِع تعمل على الكائن الحالي حتّى لو كانت التوابِع نفسها موروثة.
	</li>
	<li>
		تمرّ حلقة <code>for..in</code> على خاصيات الكائن والخاصيات الموروثة، بينما لا تعمل توابِع جلب المفاتيح/القيم إلّا على الكائن نفسه.
	</li>
</ul>
<h2>
	تمارين
</h2>

<h3>
	العمل مع prototype
</h3>

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

<p>
	إليك شيفرة تُنشئ كائنين وتعدّلها.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_25" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  jumps</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 rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal</span><span class="pun">,</span><span class="pln">
  jumps</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">

alert</span><span class="pun">(</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">jumps </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ? (1)</span><span class="pln">

</span><span class="kwd">delete</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">jumps</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">jumps </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ? (2)</span><span class="pln">

</span><span class="kwd">delete</span><span class="pln"> animal</span><span class="pun">.</span><span class="pln">jumps</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> rabbit</span><span class="pun">.</span><span class="pln">jumps </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ? (3)</span></pre>

<p>
	يجب أن هنالك ثلاث إجابات.
</p>

<h4>
	الحل
</h4>

<ol>
<li>
		‏<code>true</code>، تأتي من <code>rabbit</code>.
	</li>
	<li>
		‏<code>null</code>، تأتي من <code>animal</code>.
	</li>
	<li>
		‏<code>undefined</code>، إذ ليس هناك خاصية بهذا الاسم بعد الآن.
	</li>
</ol>
<h3>
	خوارزمية بحث
</h3>

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

<p>
	ينقسم هذا التمرين إلى قسمين.
</p>

<p>
	لديك الكائنات التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_27" style="">
<span class="pln">let head </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  glasses</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">

let table </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  pen</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">

let bed </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sheet</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  pillow</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 pockets </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  money</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2000</span><span class="pln">
</span><span class="pun">};</span></pre>

<ol>
<li>
		استعمل <code>__proto__</code> لإسناد كائنات النموذج الأولي بحيث يكون البحث عن الخاصيات بهذه الطريقة: <code>pockets</code> ثمّ <code>bed</code> ثمّ <code>table</code> ثمّ <code>head</code> (من الأسفل إلى الأعلى على التتالي). فمثلًا، قيمة <code>pockets.pen</code> تكون <code>3</code> (من <code>table</code>)، وقيمة <code>bed.glasses</code> تكون <code>1</code> (من <code>head</code>).
	</li>
	<li>
		أجِب عن هذا السؤال: ما الأسرع، أن نجلب <code>glasses</code> هكذا <code>pockets.glasses</code> أم هكذا <code>head.glasses</code>؟ قِس أداء كلّ واحدة لو لزم.
	</li>
</ol>
<h4>
	الحل
</h4>

<ol>
<li>
		<p>
			لنُضيف خاصيات <code>__proto__</code>:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_29" style="">
<span class="pln">let head </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  glasses</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">

let table </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  pen</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> head
</span><span class="pun">};</span><span class="pln">

let bed </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sheet</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  pillow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> table
</span><span class="pun">};</span><span class="pln">

let pockets </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  money</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2000</span><span class="pun">,</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> bed
</span><span class="pun">};</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> pockets</span><span class="pun">.</span><span class="pln">pen </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"> bed</span><span class="pun">.</span><span class="pln">glasses </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"> table</span><span class="pun">.</span><span class="pln">money </span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined</span></pre>

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

<h3>
	أين سيحدث التعديل؟
</h3>

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

<p>
	لدينا الكائن <code>rabbit</code> يرث من الكائن <code>animal</code>.
</p>

<p>
	لو استدعينا <code>rabbit.eat()‎</code> فأيّ الكائنين ستُعدل به الخاصية <code>full</code>، الكائن <code>animal</code> أم الكائن <code>rabbit</code>؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_31" style="">
<span class="pln">let animal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  eat</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">full </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let rabbit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> animal
</span><span class="pun">};</span><span class="pln">

rabbit</span><span class="pun">.</span><span class="pln">eat</span><span class="pun">();</span></pre>

<h4>
	الحل
</h4>

<p>
	<strong>الإجابة هي: الكائن <code>rabbit</code>.</strong>
</p>

<p>
	لأنّ قيمة <code>this</code> هي الكائن قبل النقطة، بذلك يُعدّل <code>rabbit.eat()‎</code>.
</p>

<p>
	عملية البحث عن الخاصيات تختلف تمامًا عن عملية تنفيذ تلك الخاصيات.
</p>

<p>
	نجد التابِع <code>rabbit.eat</code> سيُستدعى أولًا من كائن النموذج الأولي، وبعدها نُنفّذه على أنّ <code>this=rabbit</code>.
</p>

<h3>
	لماذا أصابت التخمة كِلا الهامسترين؟
</h3>

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

<p>
	لدينا هامسترين، واحد سريع <code>speedy</code> وآخر كسول <code>lazy</code>، والاثنين يرثان كائن الهامستر العمومي <code>hamster</code>.
</p>

<p>
	حين نُعطي أحدهما الطعام، نجد الآخر أُتخم أيضًا. لماذا ذلك؟ كيف نُصلح المشكلة؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_33" style="">
<span class="pln">let hamster </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  stomach</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">

  eat</span><span class="pun">(</span><span class="pln">food</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">stomach</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">food</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 speedy </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> hamster
</span><span class="pun">};</span><span class="pln">

let lazy </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> hamster
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// وجد هذا الهامستر الطعامَ قبل الآخر</span><span class="pln">
speedy</span><span class="pun">.</span><span class="pln">eat</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"> speedy</span><span class="pun">.</span><span class="pln">stomach </span><span class="pun">);</span><span class="pln"> </span><span class="com">// apple</span><span class="pln">

</span><span class="com">// هذا أيضًا وجده. لماذا؟ أصلِح الشيفرة.</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> lazy</span><span class="pun">.</span><span class="pln">stomach </span><span class="pun">);</span><span class="pln"> </span><span class="com">// apple</span></pre>

<h4>
	الحل
</h4>

<p>
	لنرى ما يحدث داخل الاستدعاء <code>‎speedy.eat("apple")‏</code> بدقّة.
</p>

<ol>
<li>
		<p>
			نجد التابِع <code>speedy.eat</code> في كائن النموذج الأولي الهامستر (<code>=hamster</code>)، وبعدها ننفّذه بقيمة <code>this=speedy</code> (الكائن قبل النقطة).
		</p>
	</li>
	<li>
		<p>
			بعدها تأتي مهمة البحث للتابِع <code>this.stomach.push()‎</code> ليجد خاصية المعدة <code>stomach</code> ويستدعي عليها <code>push</code>. يبدأ البحث عن <code>stomach</code> في <code>this</code> (أي في <code>speedy</code>)، ولكنّه لا يجد شيئًا.
		</p>
	</li>
	<li>
		<p>
			بعدها يتبع سلسلة الوراثة ويجد المعدة <code>stomach</code> في <code>hamster</code>.
		</p>
	</li>
	<li>
		<p>
			ثمّ يستدعي <code>push</code> عليها ويذهب الطعام في <em>معدة النموذج الأولي</em>.
		</p>
	</li>
</ol>
<p>
	بهذا تتشارك الهامسترات كلها معدةً واحدة!
</p>

<p>
	أكان <code>lazy.stomach.push(...)‎</code> أم <code>speedy.stomach.push()‎</code>، لا نجد خاصية المعدة <code>stomach</code> إلّا في كائن النموذج الأولي (إذ ليست موجودة في الكائن نفسه)، بذلك ندفع البيانات الجديدة إلى كائن النموذج الأولي.
</p>

<p>
	لاحظ كيف أنّ هذا لا يحدث لو استعملنا طريقة الإسناد البسيط <code>this.stomach=‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_35" style="">
<span class="pln">let hamster </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  stomach</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">

  eat</span><span class="pun">(</span><span class="pln">food</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// نُسند إلى this.stomach بدلًا من this.stomach.push</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">stomach </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">food</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 speedy </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   __proto__</span><span class="pun">:</span><span class="pln"> hamster
</span><span class="pun">};</span><span class="pln">

let lazy </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> hamster
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// وجد الهامستر السريع الطعام</span><span class="pln">
speedy</span><span class="pun">.</span><span class="pln">eat</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"> speedy</span><span class="pun">.</span><span class="pln">stomach </span><span class="pun">);</span><span class="pln"> </span><span class="com">// apple</span><span class="pln">

</span><span class="com">// معدة ذاك الكسول فارغة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> lazy</span><span class="pun">.</span><span class="pln">stomach </span><span class="pun">);</span><span class="pln"> </span><span class="com">// &lt;لا شيء&gt;</span></pre>

<p>
	الآن يعمل كلّ شيء كما يجب، إذ لا تبحث عملية الإسناد <code>this.stomach=‎</code> عن خاصية <code>stomach</code>، بل تكتبها مباشرةً في كائن الهامستر الّذي وجد الطعام (المستدعى قبل النقطة).
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2977_37" style="">
<span class="pln">let hamster </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  stomach</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">

  eat</span><span class="pun">(</span><span class="pln">food</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">stomach</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">food</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 speedy </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> hamster</span><span class="pun">,</span><span class="pln">
  stomach</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 lazy </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  __proto__</span><span class="pun">:</span><span class="pln"> hamster</span><span class="pun">,</span><span class="pln">
  stomach</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">
speedy</span><span class="pun">.</span><span class="pln">eat</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"> speedy</span><span class="pun">.</span><span class="pln">stomach </span><span class="pun">);</span><span class="pln"> </span><span class="com">// apple</span><span class="pln">

</span><span class="com">// معدة ذاك الكسول فارغة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> lazy</span><span class="pun">.</span><span class="pln">stomach </span><span class="pun">);</span><span class="pln"> </span><span class="com">// &lt;لا شيء&gt;</span></pre>

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

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/prototype-inheritance" rel="external nofollow">Prototypal inheritance</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">887</guid><pubDate>Mon, 25 May 2020 06:06:57 +0000</pubDate></item><item><title>&#x62C;&#x627;&#x644;&#x628;&#x627;&#x62A; &#x627;&#x644;&#x62E;&#x627;&#x635;&#x64A;&#x627;&#x62A; &#x648;&#x636;&#x627;&#x628;&#x637;&#x627;&#x62A;&#x647;&#x627; (Getters and Setters) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AC%D8%A7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%88%D8%B6%D8%A7%D8%A8%D8%B7%D8%A7%D8%AA%D9%87%D8%A7-getters-and-setters-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r882/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_05/56.jpg.e85657ea3ec901c10680fa09cea2aea6.jpg" /></p>

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

<p>
	النوع الثاني هو الجديد، وهو <em>خاصيات الوصول</em> (Accessor Properties). هي في الأساس دوال تجلب القيم وتضبطها، ولكن في الشيفرة تظهرُ لنا وكأنها خاصيات عادية.
</p>

<h2>
	الجالبات والضابطات
</h2>

<p>
	خاصيات الوصول هذه هي توابِع ”جلب“ (getter) و”ضبط“ (setter).
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2314_9" 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">get</span><span class="pln"> propName</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ‫جالب، يُستعمَل جلب قيمة الخاصية obj.propName</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  </span><span class="kwd">set</span><span class="pln"> propName</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">// ‫ضابط يُستعمَل لضبط قيمة الخاصية obj.propName إلى value</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	يعمل الجالب متى ما طلبت قراءة الخاصية <code>obj.propName</code>، والضابط… متى ما أردت إسناد قيمة <code>obj.propName = value</code>.
</p>

<p>
	لاحظ مثلًا كائن <code>user</code> له خاصيتين: اسم <code>name</code> ولقب <code>surname</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2314_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">"John"</span><span class="pun">,</span><span class="pln">
  surname</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Smith"</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	الآن نريد إضافة خاصية الاسم الكامل <code>fullName</code>، وهي <code>"John Smith"</code>. طبعًا لا نريد نسخ المعلومات ولصقها، لذا سنُنفذها باستخدام خاصية الوصول (ِget):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2314_13" 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">
  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="kwd">get</span><span class="pln"> fullName</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="kwd">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="kwd">this</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">user</span><span class="pun">.</span><span class="pln">fullName</span><span class="pun">);</span><span class="pln"> </span><span class="com">// John Smith</span></pre>

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

<p>
	الآن ليس للخاصية <code>fullName</code> إلا جالبًا، لو حاولنا إسناد قيمة لها <code>user.fullName=‎</code> فسنرى خطأً:
</p>

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

user</span><span class="pun">.</span><span class="pln">fullName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Test"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// خطأ (للخاصية جالب فقط)</span></pre>

<p>
	هيًا نُصلح الخطأ ونُضيف ضابطًا للخاصية <code>user.fullName</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2314_18" 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">
  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="kwd">get</span><span class="pln"> fullName</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="kwd">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="kwd">this</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="com">// هنا </span><span class="pln">
  </span><span class="kwd">set</span><span class="pln"> fullName</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="kwd">this</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">surname</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">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="pun">};</span><span class="pln">

</span><span class="com">// نضبط fullName كما النية بتمرير القيمة.</span><span class="pln">
user</span><span class="pun">.</span><span class="pln">fullName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Alice Cooper"</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">// Alice</span><span class="pln">
alert</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="com">// Cooper</span></pre>

<p>
	وهكذا صار لدينا الخاصية ”الوهمية“ <code>fullName</code>. يمكننا قراءتها والكتابة عليها، ولكنها في واقع الأمر، غير موجودة.
</p>

<h2>
	واصفات الوصول (Accessor Descriptors)
</h2>

<p>
	واصِفات خاصيات الوصول (Accessor Properties) تختلف عن واصِفات خاصيات البيانات (Data Properties). فليس لخاصيات الوصول قيمة <code>value</code> أو راية <code>writable</code>، بل هناك دالة <code>get</code> ودالة <code>set</code>.
</p>

<p>
	أي يمكن لواصِف الوصول أن يملك مايلي:
</p>

<ul>
<li>
		<strong><code>get</code></strong> -- دالة ليس لها وُسطاء تعمل متى ما قُرئت الخاصية.
	</li>
	<li>
		<strong><code>set</code></strong> -- دالة لها وسيط واحد تُستدعى متى ما ضُبطت الخاصية.
	</li>
	<li>
		<strong><code>enumerable</code></strong> -- خاصية قابلية الإحصاء وهي مشابهة لخاصيّات البيانات.
	</li>
	<li>
		<strong><code>configurable</code></strong> -- خاصية قابلية إعادة الضبط وهي مشابهة لخاصيّات البيانات.
	</li>
</ul>
<p>
	فمثلًا لننشئ خاصية الوصول <code>fullName</code> باستعمال التابِع <code>defineProperty</code>، يمكننا تمرير واصِفًا فيه دالة <code>get</code> ودالة <code>set</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2314_20" 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">
  surname</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Smith"</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// هنا</span><span class="pln">
</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperty</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="str">'fullName'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">get</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="kwd">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="kwd">this</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="kwd">set</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </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="kwd">this</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"> value</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="pun">});</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">fullName</span><span class="pun">);</span><span class="pln"> </span><span class="com">// John Smith</span><span class="pln">

</span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let key in user</span><span class="pun">)</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln">key</span><span class="pun">);</span><span class="pln"> </span><span class="com">// name, surname</span></pre>

<p>
	أُعيد بأنّ الخاصية إمّا تكون خاصية وصول (لها توابِع <code>get/set</code>) أو خاصية بيانات (لها قيمة <code>value</code>)، ولا تكون الاثنين معًا. فلو حاولنا تقديم <code>get</code> مع <code>value</code> في نفس الواصِف، فسنرى خطأً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2314_22" style="">
<span class="com">// خطأ: واصِف الخاصية غير صالح</span><span class="pln">
</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperty</span><span class="pun">({},</span><span class="pln"> </span><span class="str">'prop'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">get</span><span class="pun">()</span><span class="pln"> </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="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></pre>

<h2>
	الجوالب والضوابط الذكية
</h2>

<p>
	يمكننا استعمال الجوالب والضوابط كأغلفة للخاصيات ”الفعلية“، فتكون في يدنا السيطرة الكاملة على العمليات التي تؤثّر عليها. فمثلًا لو أردنا منع الأسماء القصيرة للاسم <code>user</code> فيمكن كتابة الضابِط <code>name</code> وترك القيمة في خاصية منفصلة باسم <code>‎_name</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2314_24" 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="kwd">get</span><span class="pln"> name</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_name</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  </span><span class="kwd">set</span><span class="pln"> name</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">value</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&lt;</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">
      alert</span><span class="pun">(</span><span class="str">"Name is too short, need at least 4 characters"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// الاسم قصير جدًا. أقلّ طول هو 4 محارف</span><span class="pln">
      </span><span class="kwd">return</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"> 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">

user</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">
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</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">""</span><span class="pun">;</span><span class="pln"> </span><span class="com">// الاسم قصير جدًا...</span></pre>

<p>
	هكذا نخزّن الاسم في الخاصية <code>‎_name</code> والوصول يكون عبر الجالب والضابط.
</p>

<p>
	عمليًا يمكن للشيفرة الخارجية الوصول إلى الاسم مباشرةً باستعمال <code>user._name</code>، ولكن هناك مفهوم شائع بين المطوّرين هو أنّ الخاصيات التي تبدأ بشرطة سفلية <code>"_"</code> هي خاصيات داخلية وممنوع التعديل عليها من خارج الكائن.
</p>

<h2>
	استعمالها لغرض التوافقية
</h2>

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

<p>
	لنقل مثلًا بأنّا بدأنا المشروع حيث كانت كائنات المستخدمين تستعمل خاصيات البيانات: الاسم <code>name</code> والعمر <code>age</code>:
</p>

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

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"> </span><span class="lit">25</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> john</span><span class="pun">.</span><span class="pln">age </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 25</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2314_28" 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"> birthday</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">birthday </span><span class="pun">=</span><span class="pln"> birthday</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"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="lit">1992</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">1</span><span class="pun">));</span></pre>

<p>
	ولكن… كيف سنتعامل مع الشيفرة القديمة الّتي مازالت تستعمل خاصية <code>age</code>؟
</p>

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

<p>
	إذًا لنُبقي الخاصية كما هي، ونُضيف جالبًا للخاصية تحلّ لنا المشكلة:
</p>

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

  </span><span class="com">// العمر هو الفرق بين التاريخ اليوم وتاريخ الميلاد</span><span class="pln">
  </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperty</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> </span><span class="str">"age"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">get</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      let todayYear </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">getFullYear</span><span class="pun">();</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> todayYear </span><span class="pun">-</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">birthday</span><span class="pun">.</span><span class="pln">getFullYear</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 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"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="lit">1992</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">1</span><span class="pun">));</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> john</span><span class="pun">.</span><span class="pln">birthday </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"> john</span><span class="pun">.</span><span class="pln">age </span><span class="pun">);</span><span class="pln">      </span><span class="com">// ...وعمر المستخدم أيضًا</span></pre>

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

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/property-accessors" rel="external nofollow">Property getters and setters</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">882</guid><pubDate>Tue, 19 May 2020 13:14:50 +0000</pubDate></item><item><title>&#x631;&#x627;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x62E;&#x627;&#x635;&#x64A;&#x627;&#x62A; &#x648;&#x648;&#x627;&#x635;&#x641;&#x627;&#x62A;&#x647;&#x627; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%B1%D8%A7%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%88%D9%88%D8%A7%D8%B5%D9%81%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-r881/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_05/55.jpg.86432d77db1e946a2c43637fad92d823.jpg" /></p>

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

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

<h2>
	رايات الخاصيات
</h2>

<p>
	لخصائص الكائنات (إضافةً إلى <strong>القيمة</strong> الفعلية لها) ثلاث سمات أخرى مميزة (أو ”رايات“ flags):
</p>

<ul>
<li>
		<strong>قابلية التعديل</strong> -- لو كانت بقيمة <code>true</code> فيمكننا تغيير القيمة وتعديلها، ولو لم تكن فالقيمة للقراءة فقط.
	</li>
	<li>
		<strong>قابلية الإحصاء</strong> -- لو كانت بقيمة <code>true</code>، فستقدر الحلقات على المرور على عناصرها، وإلا فلن تقدر.
	</li>
	<li>
		<strong>قابلية إعادة الضبط</strong> -- لو كانت بقيمة <code>true</code> فيمكن حذف الخاصية وتعديل هذه السمات، وإلا فلا يمكن.
	</li>
</ul>
<p>
	لم نتطرّق إلى هذه الرايات قبلًا إذ لا تظهر عادةً في الشيفرات، فحين ننشئ خاصية "بالطريقة العادية" فكلّ هذه السمات بقيمة <code>true</code>، ولكن يمكننا طبعًا تغييرها متى أردنا.
</p>

<p>
	أولًا لنعرف كيف سنرى هذه الرايات.
</p>

<p>
	يتيح لنا التابِع <a href="https://wiki.hsoub.com/JavaScript/Object/getOwnPropertyDescriptor" rel="external">Object.getOwnPropertyDescriptor</a> الاستعلامَ عن المعلومات <em>الكاملة</em> الخاصة بأيّ خاصية.
</p>

<p>
	وهذه صياغته:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8898_7" style="">
<span class="pln">let descriptor </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getOwnPropertyDescriptor</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">,</span><span class="pln"> propertyName</span><span class="pun">);</span></pre>

<ul>
<li>
		<p>
			<code>obj</code>: الكائن الّذي سنجلب معلوماته.
		</p>
	</li>
	<li>
		<p>
			<code>propertyName</code>: اسم الخاصية الّتي نريد.
		</p>
	</li>
</ul>
<p>
	نسمّي القيمة المُعادة بكائن ”واصِف الخاصيات“ (Property Descriptor)، وهو يحتوي على القيمة وجميع الرايات الّتي سبق لنا شرحها.
</p>

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

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

let descriptor </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getOwnPropertyDescriptor</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="str">'name'</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">descriptor</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="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="com">/* واصف الخاصية:
{
  "value": "John",
  "writable": true,
  "enumerable": true,
  "configurable": true
}
*/</span></pre>

<p>
	يمكننا استعمال التابِع <a href="https://wiki.hsoub.com/JavaScript/Object/defineProperty" rel="external">Object.defineProperty</a> لتغيير الرايات.
</p>

<p>
	إليك صياغته:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8898_11" style="">
<span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperty</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">,</span><span class="pln"> propertyName</span><span class="pun">,</span><span class="pln"> descriptor</span><span class="pun">)</span></pre>

<ul>
<li>
		<p>
			<code>obj</code> و <code>propertyName</code>: الكائن الّذي سنطبّق عليه الواصِف، واسم الخاصية.
		</p>
	</li>
	<li>
		<p>
			<code>descriptor</code>: واصِف الخاصيات الّذي سنطبّقه على الكائن.
		</p>
	</li>
</ul>
<p>
	لو كانت الخاصية موجودة فسيُحدّث التابع <code>defineProperty</code> راياتها. وإلّا فسيُنشئ الخاصية بهذه القيمة الممرّرة والرايات كذلك، وفي هذه الحالة لو لم يجد قيمة لأحد الرايات، فسيعدّه بقيمة <code>false</code>.
</p>

<p>
	مثلًا هنا نُنشئ الخاصية <code>name</code> حيث تكون راياتها كلّها بقيمة <code>false</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8898_14" 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="typ">Object</span><span class="pun">.</span><span class="pln">defineProperty</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="str">"name"</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">"John"</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

let descriptor </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getOwnPropertyDescriptor</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="str">'name'</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">descriptor</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="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="com">/*
{
  "value": "John",
  // لاحظ هنا
  "writable": false,
  "enumerable": false,
  "configurable": false
}
 */</span></pre>

<p>
	وازِن هذه الخاصية بتلك الّتي صنعناها أعلاه <code>user.name</code> (كالعادة): وأصبحت قيمة جميع الرايات <code>false</code>. لو لم يكن هذا ما تريده فربّما الأفضل ضبطها على <code>true</code> في كائن <code>descriptor</code>.
</p>

<p>
	لنرى الآن تأثيرات هذه الرايات في هذا المثال.
</p>

<h2>
	منع قابلية التعديل
</h2>

<p>
	لنمنع قابلية التعديل على الخاصية <code>user.name</code> (أي استحالة إسناد قيمة لها) وذلك بتغيير راية <code>writable</code>:
</p>

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

</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperty</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="str">"name"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  writable</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="com">// هنا</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

user</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">// خطأ: لا يمكن إسناد القيم إلى الخاصية ‫ `name` إذ هي للقراءة فقط</span></pre>

<p>
	الآن يستحيل على أيّ شخص تعديل اسم هذا المستخدم إلّا لو طبّقوا تابِع <code>defineProperty</code> من طرفهم ليُلغي ما فعلناه نحن.
</p>

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

<p>
	إليك نفس المثال ولكن دون إنشاء الخاصية من الصفر:
</p>

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

</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperty</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="str">"name"</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">"John"</span><span class="pun">,</span><span class="pln">
  </span><span class="com">// لو كانت الخاصيات جديدة فعلينا إسناد قيمها إسنادًا صريحًا</span><span class="pln">
  enumerable</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  configurable</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">

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><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">"Pete"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// Error</span></pre>

<h2>
	منع قابلية الإحصاء
</h2>

<p>
	الآن لنُضيف تابِع <code>toString</code> مخصّص على كائن <code>user</code>.
</p>

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

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

</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 user</span><span class="pun">)</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln">key</span><span class="pun">);</span><span class="pln"> </span><span class="com">// name, toString</span></pre>

<p>
	لو لم نرد ذلك فيمكن ضبط <code>enumerable:false</code> حينها لن نستطع أن نمرر الكائن في حلقات <code>for..in</code> كما في السلوك المبدئي:
</p>

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

</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperty</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="str">"toString"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  enumerable</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="com">// هنا</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="com">// الآن اختفى تابِع toString:</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in user</span><span class="pun">)</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln">key</span><span class="pun">);</span><span class="pln"> </span><span class="com">// name</span></pre>

<p>
	كما أنّ التابِع <code>Object.keys</code> يستثني الخاصيات غير القابلة للإحصاء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8898_24" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">(</span><span class="pln">user</span><span class="pun">));</span><span class="pln"> </span><span class="com">// name</span></pre>

<h2>
	منع قابلية إعادة الضبط
</h2>

<p>
	أحيانًا ما نرى راية ”قابلية إعادة الضبط“ ممنوعة (أي <code>configurable:false</code>) في بعض الكائنات والخاصيات المضمّنة في اللغة. لا يمكن حذف هذه الخاصية لو كانت ممنوعة (أي <code>configurable:false</code>).
</p>

<p>
	فمثلًا المتغيّر المضمّن في اللغة <code>Math.PI</code> يمنع قابلية التعديل والإحصاء وإعادة الضبط عليه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8898_26" style="">
<span class="pln">let descriptor </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getOwnPropertyDescriptor</span><span class="pun">(</span><span class="typ">Math</span><span class="pun">,</span><span class="pln"> </span><span class="str">'PI'</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">descriptor</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="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="com">/*
{
  "value": 3.141592653589793,
  "writable": false,
  "enumerable": false,
  "configurable": false
}
*/</span></pre>

<p>
	هكذا لا يقدر المبرمج على تغيير قيمة <code>Math.PI</code> ولا الكتابة عليها.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8898_28" style="">
<span class="typ">Math</span><span class="pun">.</span><span class="pln">PI </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">// خطأ</span><span class="pln">

</span><span class="com">// delete Math.PI لن تعمل أيضًا</span></pre>

<p>
	إن تفعيل خاصيّة منع قابلية إعادة الضبط هو قرار لا عودة فيه، فلا يمكننا تغيير الراية (إتاحة قابلية إعادة الضبط) باستعمال التابِع <code>defineProperty</code>.
</p>

<p>
	وللدقّة فهذا المنع يضع تقييدات أخرى على <code>defineProperty</code>:
</p>

<ol>
<li>
		منع تغيير راية قابلية إعادة الضبط <code>configurable</code>.
	</li>
	<li>
		منع تغيير راية قابلية الإحصاء <code>enumerable</code>.
	</li>
	<li>
		منع تغيير راية قابلية التعديل <code>writable: false</code> إلى القيمة <code>true</code> (ولكن العكس ممكن).
	</li>
	<li>
		منع تغيير ضابط وجالب واصف الوصول <code>get/set</code> (ولكن يمكن إسناد قيم إليه).
	</li>
</ol>
<p>
	هنا سنحدّد الخاصية <code>user.name</code> لتكون ثابتة للأبد :
</p>

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

</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperty</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="str">"name"</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">"John"</span><span class="pun">,</span><span class="pln">
  writable</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  configurable</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
</span><span class="pun">});</span><span class="pln">


</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperty</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="str">"name"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">writable</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">});</span><span class="pln"> </span><span class="com">// خطأ</span></pre>

<p>
	نلاحظ عدم إمكانية تغيير الخاصيّة <code>user.name</code> ولا حتى راياتها ولن نستطيع تطبيق هذه العمليات عليها:
</p>

<ol>
<li>
		الكتابة عليها <code>user.name = "Pete"</code>‎.
	</li>
	<li>
		حذفها <code>delete user.name</code>.
	</li>
	<li>
		تغيير قيمتها باستخدام التابع <code>defineProperty</code> هكذا: <code>defineProperty(user, "name", { value: "Pete" })‎</code>.
	</li>
</ol>
<p>
	<strong>”إن منع قابلية إعادة الضبط“ ليس ”منعًا لقابلية التعديل“</strong> إن فكرة منع قابلية إعادة الضبط هي في الحقيقة لمنع تغيير رايات هذه الخاصية أو حذفها، وليس تغيير قيمة الخاصية بحد ذاتها.
</p>

<p>
	<strong>ملاحظة</strong>: في المثال السابق جعلنا قابلية التعديل ممنوعة يدويًا.
</p>

<h2>
	التابع Object.defineProperties
</h2>

<p>
	هناك أيضًا التابِع <a href="https://wiki.hsoub.com/JavaScript/Object/defineProperties" rel="external">Object.defineProperties</a> إذ يُتيح تعريف أكثر من خاصية في وقت واحد.
</p>

<p>
	صياغته هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8898_32" style="">
<span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperties</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">
  prop1</span><span class="pun">:</span><span class="pln"> descriptor1</span><span class="pun">,</span><span class="pln">
  prop2</span><span class="pun">:</span><span class="pln"> descriptor2
  </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_8898_34" style="">
<span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperties</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">
  name</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">"John"</span><span class="pun">,</span><span class="pln"> writable</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  surname</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">"Smith"</span><span class="pun">,</span><span class="pln"> writable</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	أي أنّنا نقدر على ضبط أكثر من خاصية معًا.
</p>

<h2>
	التابع Object.getOwnPropertyDescriptors
</h2>

<p>
	يمكننا استعمال التابِع <a href="https://wiki.hsoub.com/JavaScript/Object/getOwnPropertyDescriptors" rel="external">Object.getOwnPropertyDescriptors(obj)</a>‎ لجلب كلّ واصفات الخاصيات معًا. ويمكن استعماله بدمجه مع <code>Object.defineProperties</code> لنسخ الكائنات ”ونحن على علمٍ براياتها“:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8898_36" style="">
<span class="pln">let clone </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">defineProperties</span><span class="pun">({},</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">getOwnPropertyDescriptors</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">));</span></pre>

<p>
	فعادةً حين ننسخ كائنًا نستعمل الإسناد لنسخ الخاصيات، هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8898_38" style="">
<span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  clone</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"> user</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ولكن… هذا لا ينسخ معه الرايات. لذا يفضّل استعمال <code>Object.defineProperties</code> لو أردنا نُسخةً ”أفضل“ عن الكائن.
</p>

<p>
	الفرق الثاني هو أنّ حلقة <code>for..in</code> تتجاهل الخاصيات الرمزية (Symbolic Properties)، ولكنّ التابِع <code>Object.getOwnPropertyDescriptors</code> يُعيد <em>كلّ</em> واصِفات الخاصيات بما فيها الرمزية.
</p>

<h2>
	إغلاق الكائنات على المستوى العام
</h2>

<p>
	تعمل واصِفات الخاصيات على مستوى الخاصيات منفردةً. هناك أيضًا توابِع تقصر الوصول إلى الكائن <em>كلّه</em>:
</p>

<p>
	<strong><a href="https://wiki.hsoub.com/JavaScript/Object/preventExtensions" rel="external">Object.preventExtensions(obj)</a>‎</strong>
</p>

<p>
	يمنع إضافة خاصيات جديدة إلى الكائن.
</p>

<p>
	<strong><a href="https://wiki.hsoub.com/JavaScript/Object/seal" rel="external">Object.seal(obj)</a>‎</strong>
</p>

<p>
	يمنع إضافة الخاصيات وإزالتها، فهو يمنع قابلية إعادة الضبط <code>configurable: false</code> على كلّ الخاصيات الموجودة.
</p>

<p>
	<strong><a href="https://wiki.hsoub.com/JavaScript/Object/freeze" rel="external">Object.freeze(obj)</a>‎</strong>
</p>

<p>
	يمنع إضافة الخاصيات أو إزالتها أو تغييرها، إذ يمنع قابلية التعديل <code>writable: false</code> وقابلية إعادة الضبط <code>configurable: false</code> على كلّ الخاصيات الموجودة.
</p>

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

<p>
	<strong><a href="https://wiki.hsoub.com/JavaScript/Object/isExtensible" rel="external">Object.isExtensible(obj)</a>‎</strong>
</p>

<p>
	يُعيد <code>false</code> لو كان ممنوعًا إضافة الخاصيات، وإلا <code>true</code>.
</p>

<p>
	<strong><a href="https://wiki.hsoub.com/JavaScript/Object/isSealed" rel="external">Object.isSealed(obj)</a>‎</strong>
</p>

<p>
	يُعيد <code>true</code> لو كان ممنوعًا إضافة الخاصيات أو إزالتها، وكانت كلّ خاصيات الكائن الموجودة ممنوعة من قابلية إعادة الضبط <code>configurable: false</code>.
</p>

<p>
	<strong><a href="https://wiki.hsoub.com/JavaScript/Object/isFrozen" rel="external">Object.isFrozen(obj)</a>‎</strong>
</p>

<p>
	يُعيد <code>true</code> لو كان ممنوعًا إضافة الخاصيات أو إزالتها أو تغييرها، وكانت كلّ خاصيات الكائن الموجودة ممنوعة أيضًا من قابلية التعديل <code>writable: false</code> أو إعادة الضبط <code>configurable: false</code>.
</p>

<p>
	أمّا على أرض الواقع، فنادرًا ما نستعمل هذه التوابِع.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/property-descriptors" rel="external nofollow">Property flags and descriptors</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">881</guid><pubDate>Mon, 18 May 2020 13:00:00 +0000</pubDate></item><item><title>&#x646;&#x638;&#x631;&#x629; &#x62A;&#x641;&#x635;&#x64A;&#x644;&#x64A;&#x629; &#x639;&#x644;&#x649; &#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; &#x627;&#x644;&#x633;&#x647;&#x645;&#x64A;&#x629; Arrow functions &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%86%D8%B8%D8%B1%D8%A9-%D8%AA%D9%81%D8%B5%D9%8A%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B3%D9%87%D9%85%D9%8A%D8%A9-arrow-functions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r880/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_04/54.jpg.ee57fd7617d296caa3b1bcf6b2ab798e.jpg" /></p>

<p>
	سبق وأن مررنا على الدوال السهمية مرورًا سريعًا في مقال <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D8%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/" rel="">الدوال في الكائنات واستعمالها this</a> ( وننصحك بالرجوع إليه وقراءته إن لم تكن قد قرأته مسبقًا) وتعرفنا على كيفية استخدامها استخدامًا أساسيًا وسنتعمق الآن فيها تعمقًا أكبر.
</p>

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

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

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

<ul>
<li>
		<code>‎arr.forEaoch(func)‎</code>: تُنفّذ <code>‎forEach‎</code> الدالة <code>‎func‎</code> لكلّ عنصر في المصفوفة.
	</li>
	<li>
		<code>‎setTimeut(func)‎</code>: يُنفّذ المجدول الداخلي في البيئة دالة <code>‎func‎</code>.
	</li>
	<li>
		…وغيرها وغيرها.
	</li>
</ul>
<p>
	هذا هو جوهر اللغة، أن نصنع دالة في مكان ونمرّرها إلى مكان آخر.
</p>

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

<h2>
	ليس للدوال السهمية مفهوم الأنا <code>this</code>
</h2>

<p>
	كما نذكر من فصل دوال الكائنات، this فليس في الدوال السهمية مفهوم <code>‎this‎</code>، ولو حاولت الوصول إلى قيمة <code>‎this‎</code> فستأخذها الدالة من الخارج.
</p>

<p>
	فمثلًا يمكننا استعمالها للمرور على العناصر داخل تابِع للكائن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_881_7" style="">
<span class="pln">let group </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">"Our Group"</span><span class="pun">,</span><span class="pln">
  students</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">"Pete"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Alice"</span><span class="pun">],</span><span class="pln">

  showList</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">students</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">
      student </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">title </span><span class="pun">+</span><span class="pln"> </span><span class="str">': '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> student</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">

group</span><span class="pun">.</span><span class="pln">showList</span><span class="pun">();</span></pre>

<p>
	استعملنا هنا في <code>‎forEach‎</code> الدالة السهمية، وقيمة <code>‎this.title‎</code> فيها هي تمامًا القيمة التي يراها التابِع الخارجي <code>‎showList‎</code>، أي <code>‎group.title‎</code>.
</p>

<p>
	لو استعملنا هنا الدوال العادية فسنواجه خطأً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_881_9" style="">
<span class="pln">let group </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">"Our Group"</span><span class="pun">,</span><span class="pln">
  students</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">"Pete"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Alice"</span><span class="pun">],</span><span class="pln">

  showList</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">students</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">student</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// ‫خطأ: تعذّرت قراءة الخاصية 'title' لغير المعرّف undefined</span><span class="pln">
      alert</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">title </span><span class="pun">+</span><span class="pln"> </span><span class="str">': '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> student</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">

group</span><span class="pun">.</span><span class="pln">showList</span><span class="pun">();</span></pre>

<p>
	سبب هذا الخطأ هو أنّ التابِع <code>‎forEach‎</code> يشغّل الدوال بتمرير <code>‎this=undefined‎</code> مبدئيًا، وبذلك تحاول الشيفرة الوصول إلى <code>‎undefined.title‎</code>.
</p>

<p>
	ليس لهذا أيّ تأثير على الدوال السهمية إذ ليس لها <code>‎this‎</code> أساسًا.
</p>

<p>
	<strong>لا يمكن تشغيل الدوال السهمية باستعمال <code>‎new‎</code></strong> بطبيعة الحال فدون <code>‎this‎</code> تواجه حدًّا آخر: لا يمكنك استعمال الدوال السهمية على أنّها مُنشِئات دوال، أي لا يمكنك استدعاءها باستعمال <code>‎new‎</code>.
</p>

<p>
	<strong>الدوال السهمية والربطات</strong> هناك فرق بسيط بين الدالة السهمية <code>‎=&gt;‎</code> والدالة العادية التي نستدعيها باستعمال <code>‎.bind(this)‎</code>:
</p>

<ul>
<li>
		يُنشئ التابِع <code>‎.bind(this)‎</code> «نسخة مربوطة» من تلك الدالة.
	</li>
	<li>
		لا يصنع السهم <code>‎=&gt;‎</code> أيّ نوع من الربطات. الدالة ليس فيها <code>‎this‎</code>، فقط. يبحث المحرّك عن قيمة <code>‎this‎</code> كما يبحث عن أيّ قيمة متغير آخر: في البيئة المُعجمية الخارجية للدالة السهمية.
	</li>
</ul>
<h2>
	ليس للدوال السهمية معاملات
</h2>

<p>
	كما وأنّ الدوال السهمية ليس فيها متغير مُعاملات <code>‎arguments‎</code>.
</p>

<p>
	وهذا أمر رائع حين نتعامل مع المُزخرِفات إذ نُمرّر الاستدعاء حاملًا قيمة <code>‎this‎</code> الحالية مع المُعاملات <code>‎arguments‎</code>.
</p>

<p>
	فمثلًا هنا تأخذ <code>‎defer(f, ms)‎</code> دالةً وتُعيد غِلافًا (Wrapper) عليها تُؤجّل الاستدعاء بالمليثوان <code>‎ms‎</code> الممرّرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_881_11" style="">
<span class="kwd">function</span><span class="pln"> defer</span><span class="pun">(</span><span class="pln">f</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="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">
    setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> arguments</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="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> sayHi</span><span class="pun">(</span><span class="pln">who</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="pln"> </span><span class="pun">+</span><span class="pln"> who</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let sayHiDeferred </span><span class="pun">=</span><span class="pln"> defer</span><span class="pun">(</span><span class="pln">sayHi</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2000</span><span class="pun">);</span><span class="pln">
sayHiDeferred</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>
	يمكن كتابة نفس الشيفرة دون استعمال دالة سهمية هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_881_13" style="">
<span class="kwd">function</span><span class="pln"> defer</span><span class="pun">(</span><span class="pln">f</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="kwd">return</span><span class="pln"> </span><span class="kwd">function</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">
    let ctx </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
    setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="pln">ctx</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"> ms</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هنا لزم أن نصنع المتغيرين الإضافيين <code>‎args‎</code> و <code>‎ctx‎</code> لتقدر الدالة في <code>‎setTimeout‎</code> على أخذ قيمهما.
</p>

<h2>
	ملخص
</h2>

<p>
	ليس للدوال السهمية:
</p>

<ul>
<li>
		لا <code>‎this‎</code>.
	</li>
	<li>
		ولا <code>‎arguments‎</code>.
	</li>
	<li>
		ولا يمكن استدعائها باستعمال <code>‎new‎</code>.
	</li>
	<li>
		وليس فيها <code>‎super‎</code>… لم نشرح ذلك بعد ولكنّا سنفعل في الفصل «وراثة الأصناف».
	</li>
</ul>
<p>
	ليس فيها هذا كله لأنّ الغرض منها كتابة شيفرات قصيرة ليس لها سياق تعتمد عليه بل سياقًا تأخذه، وهنا حين تتألّق هذه الدوال.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/arrow-functions" rel="external nofollow">Arrow functions revisited</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">880</guid><pubDate>Fri, 17 Apr 2020 11:13:02 +0000</pubDate></item><item><title>&#x631;&#x628;&#x637; &#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; Function binding &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%B1%D8%A8%D8%B7-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-function-binding-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r879/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_04/53.jpg.877a68a0b7302717245d26f821625111.jpg" /></p>

<p>
	ثمّة مشكلة معروفة تواجهنا متى مرّرنا توابِع الكائنات على أنّها ردود نداء (كما نفعل مع <code>‎setTimeout‎</code>)، هي ضياع هويّة الأنا <code>‎this‎</code>.
</p>

<p>
	سنرى في هذا الفصل طرائق إصلاح هذه المشكلة.
</p>

<h2>
	ضياع الأنا (الكلمة المفتاحية <code>this</code>)
</h2>

<p>
	رأينا قبل الآن أمثلة كيف ضاعت قيمة <code>‎this‎</code>. فما نلبث أن مرّرنا التابِع إلى مكان آخر منفصلًا عن كائنه، ضاع <code>‎this‎</code>.
</p>

<p>
	إليك ظواهر هذه المشكلة باستعمال <code>‎setTimeout‎</code> مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_7" 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">"John"</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="typ">Hello</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">firstName</span><span class="pun">}!‎`);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

setTimeout</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">sayHi</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">// Hello, undefined!</span></pre>

<p>
	كما رأينا في ناتج الشيفرة، لم نرحّب بالأخ John (كما أردنا باستعمال <code>‎this.firstName‎</code>)، بل بالأخ غير المعرّف <code>‎undefined‎</code>!
</p>

<p>
	هذا لأنّ التابِع <code>‎setTimeout‎</code> استلم الدالة <code>‎user.sayHi‎</code> منفصلةً عن كائنها. يمكن أن نكتب السطر الأخير هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_9" style="">
<span class="pln">let f </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">
setTimeout</span><span class="pun">(</span><span class="pln">f</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">// ‫ضاع سياق المستخدم user</span></pre>

<p>
	بالمناسبة فالتابِع <code>‎setTimeout‎</code> داخل المتصفّحات يختلف قليلًا، إذ يضبط <code>‎this=window‎</code> حين نستدعي الدالة (بينما في Node.js يصير <code>‎this‎</code> هو ذاته كائن المؤقّت، ولكنّ هذا ليس بالأمر المهم الآن). يعني ذلك بأنّ <code>‎this.firstName‎</code> هنا هي فعليًا <code>‎window.firstName‎</code>، وهذا المتغير غير موجود. عادةً ما تصير <code>‎this‎</code> غير معرّفة <code>‎undefined‎</code> في الحالات الأخرى.
</p>

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

<h2>
	الحل رقم واحد: نستعمل دالة مغلفة
</h2>

<p>
	أسهل الحلول هو استعمال دالة غالِفة <em>Wrapping function</em>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_11" 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">"John"</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="typ">Hello</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">firstName</span><span class="pun">}!‎`);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  user</span><span class="pun">.</span><span class="pln">sayHi</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"> </span><span class="lit">1000</span><span class="pun">);</span></pre>

<p>
	الآن اكتملت المهمة إذ استلمنا المستخدم <code>‎user‎</code> من البيئة المُعجمية الخارجية، وثمّ استدعينا التابِع كما العادة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_13" style="">
<span class="pln">setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</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="lit">1000</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hello, John!</span></pre>

<p>
	ممتازة جدًا، ولكن ستظهر لنا نقطة ضعف في بنية الشيفرة.
</p>

<p>
	ماذا لو حدث وتغيّرت قيمة <code>‎user‎</code> قبل أن تعمل <code>‎setTimeout‎</code>؟ (لا تنسَ التأخير، ثانية كاملة!) حينها سنجد أنّا استدعينا الكائن الخطأ دون أن ندري!
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_15" 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">"John"</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="typ">Hello</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">firstName</span><span class="pun">}!‎`);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">sayHi</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">// ‫...تغيّرت قيمة user خلال تلك الثانية</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"> alert</span><span class="pun">(</span><span class="str">"Another user in setTimeout!"</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">// setTimeout! هناك مستخدم آخر داخل التابِع‏</span></pre>

<p>
	الحل الثاني سيضمن لنا ألّا تحدث هكذا أمور غير متوقّعة.
</p>

<h2>
	الحل رقم اثنين: ربطة
</h2>

<p>
	تقدّم لنا الدوال تابِعًا مضمّنًا في اللغة باسم <a href="https://wiki.hsoub.com/JavaScript/Function/bind" rel="external">bind</a> يتيح لنا ضبط قيمة <code>‎this‎</code>.
</p>

<p>
	إليك صياغته الأساسية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_17" style="">
<span class="com">// ستأتي الصياغة المعقّدة لاحقًا لا تقلق</span><span class="pln">
let boundFunc </span><span class="pun">=</span><span class="pln"> func</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="pln">context</span><span class="pun">);</span></pre>

<p>
	ناتِج التابِع <code>‎func.bind(context)‎</code> هو «كائن دخيل» يشبه الدالة ويمكن لنا استدعائه على أنّه دالة، وسيمرّر هذا الاستدعاء إلى <code>‎func‎</code> بعدما يضبط <code>‎this=context‎</code> من خلف الستار.
</p>

<p>
	أي بعبارة أخرى، لو استدعينا <code>‎boundFunc‎</code> فكأنّما استدعينا <code>‎func‎</code> بعدما ضبطنا قيمة <code>‎this‎</code>.
</p>

<p>
	إليك مثالًا تمرّر فيه <code>‎funcUser‎</code> الاستدعاء إلى <code>‎func‎</code> بضبط <code>‎this=user‎</code>:
</p>

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

</span><span class="kwd">function</span><span class="pln"> func</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">firstName</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let funcUser </span><span class="pun">=</span><span class="pln"> func</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="pln">user</span><span class="pun">);</span><span class="pln">
funcUser</span><span class="pun">();</span><span class="pln"> </span><span class="com">// John  </span></pre>

<p>
	رأينا «النسخة الرابطة» من <code>‎func‎</code>، ‏<code>‎func.bind(user)‎</code> بعد ضبط <code>‎this=user‎</code>.
</p>

<p>
	كما أنّ المُعاملات كلّها تُمرّر إلى دالة <code>‎func‎</code> الأًصلية «كما هي». مثال:
</p>

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

</span><span class="kwd">function</span><span class="pln"> func</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">
  alert</span><span class="pun">(</span><span class="pln">phrase </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="kwd">this</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">

</span><span class="com">// ‫نربط this إلى user</span><span class="pln">
let funcUser </span><span class="pun">=</span><span class="pln"> func</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="pln">user</span><span class="pun">);</span><span class="pln">

funcUser</span><span class="pun">(</span><span class="str">"Hello"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫Hello, John (مُرّر المُعامل "Hello" كما وُضبط this=user)</span></pre>

<p>
	فلنجرّب الآن مع تابع لكائن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_23" 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">"John"</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="typ">Hello</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">firstName</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 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">bind</span><span class="pun">(</span><span class="pln">user</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (*)</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">// Hello, John!</span><span class="pln">

setTimeout</span><span class="pun">(</span><span class="pln">sayHi</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">// Hello, John!</span><span class="pln">

</span><span class="com">// ‫حتّى لو تغيّرت قيمة user خلال تلك الثانية</span><span class="pln">
</span><span class="com">// ‫فما زالت تستعمل sayHi القيمة التي ربطناها قبلًا</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"> alert</span><span class="pun">(</span><span class="str">"Another user in setTimeout!"</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	أخذنا في السطر <code>‎(*)‎</code> التابِع <code>‎user.sayHi‎</code> وربطناه مع المستخدم <code>‎user‎</code>. ندعو الدالة <code>‎sayHi‎</code> بالدالة «المربوطة» حيث يمكن أن نستدعيها لوحدها هكذا أو نمرّرها إلى <code>‎setTimeout‎</code>. مهما فعلًا فسيكون السياق صحيحًا كما نريد.
</p>

<p>
	نرى هنا أنّ المُعاملات مُرّرت «كما هي» وما ضبطه <code>‎bind‎</code> هو قيمة <code>‎this‎</code> فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_25" 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">"John"</span><span class="pun">,</span><span class="pln">
  say</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">
    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="kwd">this</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">
</span><span class="pun">};</span><span class="pln">

let say </span><span class="pun">=</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">say</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="pln">user</span><span class="pun">);</span><span class="pln">

say</span><span class="pun">(</span><span class="str">"Hello"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫Hello, John!‎ (مُرّر المُعامل "Hello" إلى say)</span><span class="pln">
say</span><span class="pun">(</span><span class="str">"Bye"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫Bye, John!‎ (مُرّر المعامل "Bye" إلى say)</span></pre>

<p>
	<strong>تابِع مفيد: <code>‎bindAll‎</code></strong> لو كان للكائن توابِع كثيرة وأردنا تمريرها هنا وهناك بكثرة، فربّما نربطها كلّها في حلقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_27" style="">
<span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">typeof</span><span class="pln"> user</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="str">'function'</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">key</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">key</span><span class="pun">].</span><span class="pln">bind</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></pre>

<p>
	كما تقدّم لنا مكتبات جافاسكربت دوال للربط الجماعي لتسهيل الأمور، مثل <a href="http://lodash.com/docs#bindAll" rel="external nofollow"><code>‎_.bindAll(obj)‎</code></a> في المكتبة lodash.
</p>

<h2>
	الدوال الجزئية
</h2>

<p>
	طوال هذه الفترة لم نُناقش شيئًا إلّا ربط <code>‎this‎</code>. لنُضيف شيئًا آخر على الطاولة.
</p>

<p>
	يمكن أيضًا أن نربط المُعاملات وليس <code>‎this‎</code> فحسب. صحيح أنّا نادرًا ما نفعل ذلك إلّا أنّ الأمر مفيد في أحيان عصيبة.
</p>

<p>
	صياغة <code>‎bind‎</code> الكاملة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_29" style="">
<span class="pln">let bound </span><span class="pun">=</span><span class="pln"> func</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="pln">context</span><span class="pun">,</span><span class="pln"> </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">arg2</span><span class="pun">],</span><span class="pln"> </span><span class="pun">...);</span></pre>

<p>
	وهي تسمح لنا بربط السياق ليكون <code>‎this‎</code> والمُعاملات الأولى في الدالة.
</p>

<p>
	نرى مثالًا: دالة ضرب <code>‎mul(a, b)‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_32" style="">
<span class="kwd">function</span><span class="pln"> mul</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></pre>

<p>
	فلنستعمل <code>‎bind‎</code> لنصنع دالة «ضرب في اثنين» <code>‎double‎</code> تتّخذ تلك أساسًا لها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_34" style="">
<span class="kwd">function</span><span class="pln"> mul</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">

let </span><span class="kwd">double</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> mul</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</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">

alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">double</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">// = mul(2, 3) = 6</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">double</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="com">// = mul(2, 4) = 8</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">double</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">// = mul(2, 5) = 10</span></pre>

<p>
	يصنع استدعاء <code>‎mul.bind(null, 2)‎</code> دالةً جديدة <code>‎double‎</code> تُمرّر الاستدعاءات إلى <code>‎mul‎</code> وتضبط <code>‎null‎</code> ليكون السياق و<code>‎2‎</code> ليكون المُعامل الأول. الباقي من مُعاملات يُمرّر «كما هو».
</p>

<p>
	هذا ما نسمّيه <a href="https://en.wikipedia.org/wiki/Partial_application" rel="external nofollow">باستعمال الدوال الجزئية</a> -- أن نصنع دالة بعد ضبط بعض مُعاملات واحدة غيرها.
</p>

<p>
	لاحظ هنا بأنّا لا نستعمل <code>‎this‎</code> هنا أصلًا… ولكنّ التابِع <code>‎bind‎</code> يطلبه فعلينا تقديم شيء (وكان <code>‎null‎</code> مثلًا).
</p>

<p>
	الدالة <code>‎triple‎</code> أسفله تضرب القيمة في ثلاثة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_36" style="">
<span class="kwd">function</span><span class="pln"> mul</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">

let triple </span><span class="pun">=</span><span class="pln"> mul</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">null</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"> triple</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">// = mul(3, 3) = 9</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> triple</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="com">// = mul(3, 4) = 12</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> triple</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">// = mul(3, 5) = 15</span></pre>

<p>
	ولكن لماذا نصنع الدوال الجزئية أصلًا، وعادةً؟!
</p>

<p>
	الفائدة هي إنشاء دالة مستقلة لها اسم سهل القراءة (<code>‎double‎</code> أو <code>‎triple‎</code>)، فنستعملها دون تقديم المُعامل الأول في كلّ مرة إذ ضبطنا قيمته باستعمال <code>‎bind‎</code>.
</p>

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

<p>
	فمثلًا يمكن أن نصنع الدالة <code>‎send(from, to, text)‎</code>. وبعدها في كائن المستخدم <code>‎user‎</code> نصنع نسخة جزئية عنها: <code>‎sendTo(to, text)‎</code> تُرسل النصّ من المستخدم الحالي.
</p>

<h2>
	الجزئية، بدون السياق
</h2>

<p>
	ماذا لو أردنا أن نضبط بعض المُعاملات ولكن دون السياق <code>‎this‎</code>؟ مثلًا نستعملها لتابِع أحد الكائنات.
</p>

<p>
	تابِع <code>‎bind‎</code> الأصيل في اللغة لا يسمح بذلك، ومستحيل أن نُزيل السياق ونضع المُعاملات فقط.
</p>

<p>
	لكن لحسن الحظ فيمكننا صنع دالة مُساعدة <code>‎partial‎</code> تربط المُعاملات فقط.
</p>

<p>
	هكذا تمامًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_38" style="">
<span class="kwd">function</span><span class="pln"> partial</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">argsBound</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">args</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"> func</span><span class="pun">.</span><span class="pln">call</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">argsBound</span><span class="pun">,</span><span class="pln"> </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="pun">}</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="pun">{</span><span class="pln">
  firstName</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">,</span><span class="pln">
  say</span><span class="pun">(</span><span class="pln">time</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">
    alert</span><span class="pun">(`‎[</span><span class="pln">$</span><span class="pun">{</span><span class="pln">time</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">firstName</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">
</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">sayNow </span><span class="pun">=</span><span class="pln"> partial</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">say</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">getHours</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"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">().</span><span class="pln">getMinutes</span><span class="pun">());</span><span class="pln">

user</span><span class="pun">.</span><span class="pln">sayNow</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">
</span><span class="com">// [10:00] John: Hello!</span></pre>

<p>
	ناتِج استدعائنا للدالة <code>‎partial(func[, arg1, arg2...])‎</code> هو غِلاف <code>‎(*)‎</code> يستدعي الدالة <code>‎func‎</code> هكذا:
</p>

<ul>
<li>
		يترك <code>‎this‎</code> كما هو (فتكون قيمته <code>‎user‎</code> داخل الاستدعاء <code>‎user.sayNow‎</code>)
	</li>
	<li>
		ثمّ يمرّر لها <code>‎...argsBound‎</code>: أي المُعاملات من استدعاء <code>‎partial‎</code> ‏(<code>‎"10:00"‎</code>)
	</li>
	<li>
		وثمّ يمرّر لها <code>‎...args‎</code>: المُعاملات الممرّرة للغِلاف (<code>‎"Hello"‎</code>)
	</li>
</ul>
<p>
	ساعدنا مُعامل التوزيع كثيرًا هنا، أم لا؟
</p>

<p>
	كما أنّ هناك شيفرة <a href="https://lodash.com/docs#partial" rel="external nofollow"><code>‎_.partial</code></a> في المكتبة lodash.
</p>

<h2>
	ملخص
</h2>

<p>
	يُعيد التابِع <code>‎func.bind(context, ...args)‎</code> «نسخة مربوطة» من الدالة <code>‎func‎</code> بعد ضبط سياقها <code>‎this‎</code> ومُعاملاتها الأولى (في حال مرّرناها).
</p>

<p>
	عادةً ما نستعمل <code>‎bind‎</code> لنضبط <code>‎this‎</code> داخل تابِع لأحد الكائنات، فيمكن أن نمرّر التابِع ذلك إلى مكان آخر، مثلًا إلى <code>‎setTimeout‎</code>.
</p>

<p>
	وحين نضبط بعضًا من مُعاملات إحدى الدوال، يكون الناتج (وهو أكثر تفصيلًا) دالةً ندعوها بالدالة <em>الجزئية</em> أو <em>المطبّقة بنحوٍ جزئي</em> <em>partially applied</em>.
</p>

<p>
	تُفيدنا هذه الدوال الجزئية حين لا نريد تكرار ذات الوسيط مرارًا وتكرارًا، مثل دالة <code>‎send(from, to)‎</code> حيث يجب أن يبقى <code>‎from‎</code> كما هو في مهمّتنا هذه، فنأخذ دالة جزئية ونتعامل بها.
</p>

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

<h3>
	دالة ربط على أنها تابِع
</h3>

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

<p>
	ما ناتج هذه الشيفرة؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_40" 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">
  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="com">// ؟</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="pun">{</span><span class="pln">
  g</span><span class="pun">:</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">bind</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">

user</span><span class="pun">.</span><span class="pln">g</span><span class="pun">();</span></pre>

<h4>
	الحل
</h4>

<p>
	الجواب هو: <code>‎null‎</code>.
</p>

<p>
	سياق دالة الربط مكتوب في الشيفرة (hard-coded) ولا يمكن تغييره لاحقًا بأيّ شكل من الأشكال.
</p>

<p>
	فحتّى لو شغّلنا <code>‎user.g()‎</code> فستُستدعى الدالة الأصلية بضبط <code>‎this=null‎</code>.
</p>

<h3>
	ربطة ثانية
</h3>

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

<p>
	هي يمكن أن نغيّر قيمة <code>‎this‎</code> باستعمال ربطة إضافية؟
</p>

<p>
	ما ناتج هذه الشيفرة؟
</p>

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

f </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">bind</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">bind</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="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

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

<h4>
	الحل
</h4>

<p>
	الجواب هو: <strong>John</strong>.
</p>

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

f </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">bind</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">bind</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="pun">);</span><span class="pln">

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

<p>
	لا يتذكّر كائن <a href="https://tc39.github.io/ecma262/#sec-bound-function-exotic-objects" rel="external nofollow">دالة الربط</a> «الدخيل» (الذي يُعيده <code>‎f.bind(...)‎</code>) السياق (مع الوُسطاء إن مُرّرت) - لا يتذكّر هذا كلّه إلى وقت إنشاء الكائن.
</p>

<p>
	أي: لا يمكن إعادة ربط الدوال.
</p>

<h3>
	خاصية الدالة بعد الربط
</h3>

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

<p>
	تمتلك خاصية إحدى الدوال قيمة ما. هل ستتغيّر بعد <code>‎bind‎</code>؟ نعم، لماذا؟ لا، لماذا؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_46" 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><span class="pln">
sayHi</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">

let bound </span><span class="pun">=</span><span class="pln"> sayHi</span><span class="pun">.</span><span class="pln">bind</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">

alert</span><span class="pun">(</span><span class="pln"> bound</span><span class="pun">.</span><span class="pln">test </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ما الناتج؟ لماذا؟</span></pre>

<h4>
	الحل
</h4>

<p>
	الجواب هو: <code>‎undefined‎</code>.
</p>

<p>
	ناتِج <code>‎bind‎</code> هو كائن آخر، وليس في هذا الكائن خاصية <code>‎test‎</code>.
</p>

<h3>
	أصلِح هذه الدالة التي يضيع this منها
</h3>

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

<p>
	على الاستدعاء <code>‎askPassword()‎</code> في الشيفرة أسفله فحص كلمة السر، ثمّ استدعاء <code>‎user.loginOk/loginFail‎</code> حسب نتيجة الفحص.
</p>

<p>
	ولكن أثناء التنفيذ نرى خطأً. لماذا؟
</p>

<p>
	أصلِح الجزء الذي فيه <code>‎(*)‎</code> لتعمل الشيفرة كما يجب (تغيير بقية الأسطر ممنوع).
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_48" style="">
<span class="kwd">function</span><span class="pln"> askPassword</span><span class="pun">(</span><span class="pln">ok</span><span class="pun">,</span><span class="pln"> fail</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let password </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"Password?"</span><span class="pun">,</span><span class="pln"> </span><span class="str">''</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">password </span><span class="pun">==</span><span class="pln"> </span><span class="str">"rockstar"</span><span class="pun">)</span><span class="pln"> ok</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> fail</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="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">

  loginOk</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="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> logged in</span><span class="pun">‎`);</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  loginFail</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="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> failed to log in</span><span class="pun">‎`);</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

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

askPassword</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">loginOk</span><span class="pun">,</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">loginFail</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (*)</span></pre>

<h4>
	الحل
</h4>

<p>
	سبب الخطأ هو أنّ الدالة <code>‎ask‎</code> تستلم الدالتين <code>‎loginOk/loginFail‎</code> دون كائنيهما.
</p>

<p>
	فمتى ما استدعتهما، تُعدّ <code>‎this=undefined‎</code> بطبيعتها.
</p>

<p>
	علينا ربط السياق!
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_50" style="">
<span class="kwd">function</span><span class="pln"> askPassword</span><span class="pun">(</span><span class="pln">ok</span><span class="pun">,</span><span class="pln"> fail</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let password </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"Password?"</span><span class="pun">,</span><span class="pln"> </span><span class="str">''</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">password </span><span class="pun">==</span><span class="pln"> </span><span class="str">"rockstar"</span><span class="pun">)</span><span class="pln"> ok</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> fail</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="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">

  loginOk</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="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> logged in</span><span class="pun">‎`);</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  loginFail</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="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> failed to log in</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">// (*)\maskPassword(user.loginOk.bind(user), user.loginFail.bind(user));</span></pre>

<p>
	الآن صارت تعمل.
</p>

<p>
	أو، بطريقة أخرى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_52" style="">
<span class="com">//...</span><span class="pln">
askPassword</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">loginOk</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"> user</span><span class="pun">.</span><span class="pln">loginFail</span><span class="pun">());</span></pre>

<p>
	هذه الشيفرة تعمل وعادةً ما تكون سهلة القراءة أيضًا.
</p>

<p>
	ولكنّها في حالات أكثر تعقيدًا تصير أقلّ موثوقية، مثل لو تغيّر المتغير <code>‎user‎</code> <em>بعدما</em> استُدعيت الدالة <code>‎askPassword‎</code> و<em>قبل</em> أن يُجيب الزائر على الاستدعاء <code>‎() =&gt; user.loginOk()‎</code>.
</p>

<h3>
	استعمال الدوال الجزئية لولوج المستخدم
</h3>

<p>
	هذا التمرين معقّد أكثر من سابقه، بقليل.
</p>

<p>
	هنا تعدّل كائن <code>‎user‎</code>، فصار فيه بدل الدالتين <code>‎loginOk/loginFail‎</code> دالة واحدة <code>‎user.login(true/false)‎</code>.
</p>

<p>
	ما الأشياء التي نمرّرها إلى <code>‎askPassword‎</code> في الشيفرة أسفله فتستدعي <code>‎user.login(true)‎</code> باستعمال <code>‎ok‎</code> وتستدعي <code>‎user.login(false)‎</code> باستعمال <code>‎fail‎</code>؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_55" style="">
<span class="kwd">function</span><span class="pln"> askPassword</span><span class="pun">(</span><span class="pln">ok</span><span class="pun">,</span><span class="pln"> fail</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let password </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"Password?"</span><span class="pun">,</span><span class="pln"> </span><span class="str">''</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">password </span><span class="pun">==</span><span class="pln"> </span><span class="str">"rockstar"</span><span class="pun">)</span><span class="pln"> ok</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> fail</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="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">

  login</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">
    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">result </span><span class="pun">?</span><span class="pln"> </span><span class="str">' logged in'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">' failed to log in'</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">

askPassword</span><span class="pun">(?,</span><span class="pln"> </span><span class="pun">?);</span><span class="pln"> </span><span class="com">// ؟ (*)</span></pre>

<p>
	يجب أن تعدّل الجزء الذي عليه <code>‎(*)‎</code> فقط لا غير.
</p>

<h4>
	الحل
</h4>

<ol>
<li>
		<p>
			نستعمل دالة غالِفة… سهمية لو أردنا التفصيل:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_57" style="">
<span class="pln">askPassword</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">login</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="pun">=&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">login</span><span class="pun">(</span><span class="kwd">false</span><span class="pun">));</span><span class="pln"> </span></pre>

		<p>
			هكذا تأخذ <code>‎user‎</code> من المتغيرات الخارجية وتُشغّل الدوال بالطريقة العادية.
		</p>
	</li>
	<li>
		<p>
			أو نصنع دالة جزئية من <code>‎user.login‎</code> تستعمل <code>‎user‎</code> سياقًا لها ونضع مُعاملها الأول كما يجب:
		</p>

		<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_740_59" style="">
<span class="pln">askPassword</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">login</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">),</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">login</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">));</span><span class="pln"> </span></pre>

		<p>
			 
		</p>
	</li>
</ol>
<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/bind" rel="external nofollow">Function binding</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">879</guid><pubDate>Fri, 17 Apr 2020 06:29:46 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x632;&#x62E;&#x631;&#x641;&#x627;&#x62A; decorators &#x648;&#x627;&#x644;&#x62A;&#x645;&#x631;&#x64A;&#x631; forwarding &#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%B2%D8%AE%D8%B1%D9%81%D8%A7%D8%AA-decorators-%D9%88%D8%A7%D9%84%D8%AA%D9%85%D8%B1%D9%8A%D8%B1-forwarding-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r878/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_04/52.jpg.51131c8b78251491ab323b3a761b3bcc.jpg" /></p>
<p>
	تقدّم لنا لغة جافاسكربت مرونة عالية غير مسبوقة في التعامل مع الدوال، إذ يمكننا تمريرها أو استعمالها على أنّها كائنات. والآن سنرى كيف <em>نمرر</em> الاستدعاءات بينها وكيف <em>نزخرفها</em>.
</p>

<h2>
	خبيئة من خلف الستار
</h2>

<p>
	لنقل بأنّ أمامنا الدالة الثقيلة على المعالج <code>‎slow(x)‎</code> بينما نتائجها مستقرة، أي لنقل بأنّنا لو مرّرنا ذات <code>‎x‎</code>، فسنجد ذات النتيجة دومًا.
</p>

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

<p>
	ولكن، بدل إضافة هذه الميزة في دالة <code>‎slow()‎</code> نفسها، سنُنشئ دالة غالِفة تُضيف ميزة الخبيئة هذه. سنرى أسفله مدى فوائد هذا الأمر.
</p>

<p>
	إليك الشيفرة أولًا، وبعدها الشرح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_7" style=""><span class="kwd">function</span><span class="pln"> slow</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="com">// هنا مهمّة ثقيلة تُهلك المعالج</span><span class="pln">
  alert</span><span class="pun">(`‎</span><span class="typ">Called</span><span class="pln"> </span><span class="kwd">with</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">x</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">function</span><span class="pln"> cachingDecorator</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">
  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="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">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">x</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"> cache</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">x</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 result </span><span class="pun">=</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">x</span><span class="pun">);</span><span class="pln">  </span><span class="com">// وإلّا نستدعي الدالة</span><span class="pln">

    cache</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> result</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"> result</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

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

alert</span><span class="pun">(</span><span class="pln"> slow</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">// خبّأنا slow(1)</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Again: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> slow</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">

alert</span><span class="pun">(</span><span class="pln"> slow</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">// ‫خبّأنا slow(2)‎</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Again: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> slow</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">// ذات ناتج السطر السابق</span></pre>

<p>
	في الشيفرة أعلاه، ندعو <code>‎cachingDecorator‎</code> <em>بالمُزخرِف</em> (decorator): وهي دالة خاصّة تأخذ دالة أخرى مُعاملًا وتعدّل على سلوكها.
</p>

<p>
	الفكرة هنا هي استدعاء <code>‎cachingDecorator‎</code> لأيّ دالة أردنا، وستُعيد لنا غِلاف الخبيئة ذاك. الفكرة هذه رائعة إذ يمكن أن نكون أمام مئات من الدوال التي يمكن أن تستغلّ هذه الميزة، وكلّ ما علينا فعله هو إضافة <code>‎cachingDecorator‎</code> عليها.
</p>

<p>
	كما وأنّا نحافظ على الشيفرة أبسط بفصل ميزة الخبيئة عن مهمّة الدالة الفعلية.
</p>

<p>
	ناتج <code>‎cachingDecorator(func)‎</code> هو «غِلاف» يُعيد الدالة <code>‎function(x)‎</code> التي «تُغلّف» استدعاء <code>‎func(x)‎</code> داخل شيفرة الخبيئة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="42605" href="https://academy.hsoub.com/uploads/monthly_2020_04/decorator-makecaching-wrapper.png.5b28c5a2a39a940ff5feb6241a817801.png" rel="" data-fileext="png"><img alt="decorator-makecaching-wrapper.png" class="ipsImage ipsImage_thumbnailed" data-fileid="42605" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/decorator-makecaching-wrapper.png.5b28c5a2a39a940ff5feb6241a817801.png"></a>
</p>

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

<p>
	إذًا نُلخّص: ثمّة فوائد عدّة لاستعمال <code>‎cachingDecorator‎</code> منفصلًا بدل تعديل شيفرة الدالة <code>‎slow‎</code> نفسها:
</p>

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

<h2>
	استعمال <code>‎func.call‎</code> لأخذ السياق
</h2>

<p>
	لا ينفع مُزخرِف الخبيئة الذي شرحناه مع توابِع الكائنات.
</p>

<p>
	فمثلًا في الشيفرة أسفله، سيتوقّف عمل <code>‎worker.slow()‎</code> بعد هذه الزخرفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_9" style=""><span class="com">// ‫هيًا نُضف ميزة الخبيئة إلى worker.slow</span><span class="pln">
let worker </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  someMethod</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  slow</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="com">// أمامنا مهمّة ثقيلة على المعالج هنا </span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"Called with "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x</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="kwd">this</span><span class="pun">.</span><span class="pln">someMethod</span><span class="pun">();</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// نفس الشيفرة أعلاه</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> cachingDecorator</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">
  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="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">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">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"> cache</span><span class="pun">.</span><span class="kwd">get</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">
    let result </span><span class="pun">=</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">x</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (**)</span><span class="pln">
    cache</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> result</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">
</span><span class="pun">}</span><span class="pln">

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

worker</span><span class="pun">.</span><span class="pln">slow </span><span class="pun">=</span><span class="pln"> cachingDecorator</span><span class="pun">(</span><span class="pln">worker</span><span class="pun">.</span><span class="pln">slow</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"> worker</span><span class="pun">.</span><span class="pln">slow</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">// ‫لاااا! خطأ: تعذّرت قراءة الخاصية 'someMethod' في undefined</span></pre>

<p>
	مكان الخطأ هو السطر <code>‎(*)‎</code> الذي يحاول الوصول إلى <code>‎this.someMethod‎</code> ويفشل فشلًا ذريعًا. هل تعرف السبب؟
</p>

<p>
	السبب هو أنّ الغِلاف يستدعي الدالة الأصلية هكذا <code>‎func(x)‎</code> في السطر <code>‎(**)‎</code>. وحين نستدعيها هكذا تستلم الدالة <code>‎this = undefined‎</code>.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_11" style=""><span class="pln">let func </span><span class="pun">=</span><span class="pln"> worker</span><span class="pun">.</span><span class="pln">slow</span><span class="pun">;</span><span class="pln">
func</span><span class="pun">(</span><span class="lit">2</span><span class="pun">);</span></pre>

<p>
	إذًا… يُمرّر الغِلاف الاستدعاء إلى التابِع الأصلي دون السياق <code>‎this‎</code>، بهذا يحصل الخطأ.
</p>

<p>
	وقت الإصلاح.
</p>

<p>
	ثمّة تابِع دوال مضمّن في اللغة باسم <a href="https://wiki.hsoub.com/JavaScript/Function/call" rel="external">func.call(context, …args)</a><code>‎</code> يتيح لنا استدعاء الدالة
</p>

<p>
	صياغته هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_13" style=""><span class="pln">func</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="pln">context</span><span class="pun">,</span><span class="pln"> arg1</span><span class="pun">,</span><span class="pln"> arg2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...)</span></pre>

<p>
	يُشغّل التابِع الدالةَ <code>‎func‎</code> بعد تمرير المُعامل الأول (وهو <code>‎this‎</code>) وثمّ مُعاملاتها.
</p>

<p>
	للتبسيط، هذين الاستدعاءين لا يفرقان بشيء في التنفيذ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_15" style=""><span class="pln">func</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">
func</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="pln">obj</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></pre>

<p>
	فكلاهما يستدعي <code>‎func‎</code> بالمُعاملات <code>‎1‎</code> و<code>‎2‎</code> و<code>‎3‎</code>. الفرق الوحيد هو أنّ <code>‎func.call‎</code> تضبط قيمة <code>‎this‎</code> على <code>‎obj‎</code> علاوةً على ذلك.
</p>

<p>
	لنأخذ مثالًا. في الشيفرة أسفله نستدعي <code>‎sayHi‎</code> بسياق كائنات أخرى: يُشغّل <code>‎sayHi.call(user)‎</code> الدالةَ <code>‎sayHi‎</code> ويُمرّر <code>‎this=user‎</code>، ثمّ في السطر التالي يضبط <code>‎this=admin‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_19" 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">name</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="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="com">// ‫نستعمل call لنمرّر مختلف الكائنات على أنّها this:</span><span class="pln">
sayHi</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="pln"> user </span><span class="pun">);</span><span class="pln"> </span><span class="com">// this = John</span><span class="pln">
sayHi</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="pln"> admin </span><span class="pun">);</span><span class="pln"> </span><span class="com">// this = Admin</span></pre>

<p>
	وهنا نستدعي <code>‎call‎</code> لتستدعي <code>‎say‎</code> بالسياق والعبارة المُمرّرتين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_21" style=""><span class="kwd">function</span><span class="pln"> say</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">
  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="str">': '</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">

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">

</span><span class="com">// ‫الكائن user يصير this وتصير Hello المُعامل الأول</span><span class="pln">
say</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="pln"> user</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"> </span><span class="com">// John: Hello</span></pre>

<p>
	في حالتنا نحن، يمكن استعمال <code>‎call‎</code> في الغِلاف ليُمرّر السياق إلى الدالة الأصلية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_23" style=""><span class="pln">let worker </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  someMethod</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  slow</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">
    alert</span><span class="pun">(</span><span class="str">"Called with "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x</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="kwd">this</span><span class="pun">.</span><span class="pln">someMethod</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="kwd">function</span><span class="pln"> cachingDecorator</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">
  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="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">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">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"> cache</span><span class="pun">.</span><span class="kwd">get</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">
    let result </span><span class="pun">=</span><span class="pln"> func</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫هكذا نُمرّر «this» كما ينبغي</span><span class="pln">
    cache</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> result</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">
</span><span class="pun">}</span><span class="pln">

worker</span><span class="pun">.</span><span class="pln">slow </span><span class="pun">=</span><span class="pln"> cachingDecorator</span><span class="pun">(</span><span class="pln">worker</span><span class="pun">.</span><span class="pln">slow</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"> worker</span><span class="pun">.</span><span class="pln">slow</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">// يعمل</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> worker</span><span class="pun">.</span><span class="pln">slow</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">// ‫يعمل ولا يستدعي التابِع الأصلي (إذ القيمة مُخبّأة)</span></pre>

<p>
	الآن يعمل كلّ شيء كما نريد.
</p>

<p>
	لنوضّح الأمر أكثر، لنرى بالتفصيل المملّ تمريرات <code>‎this‎</code> من هنا إلى هناك:
</p>

<ol>
	<li>
		بعد الزخرفة، يصير <code>‎worker.slow‎</code> الغِلاف <code>‎function (x) { ... }‎</code>.
	</li>
	<li>
		لذا حين نُنفّذ <code>‎worker.slow(2)‎</code>، يأخذ الغِلاف القيمةَ <code>‎2‎</code> وسيطًا ويضبط <code>‎this=worker‎</code> (وهو الكائن قبل النقطة).
	</li>
	<li>
		في الغِلاف (باعتبار أنّ النتيجة لم تُخبّأ بعد)، تُمرّر <code>‎func.call(this, x)‎</code> قيمة <code>‎this‎</code> الحالية (وهي <code>‎worker‎</code>) مع المُعامل الحالي (<code>‎2‎</code>) - كلّه إلى التابِع الأصلي.
	</li>
</ol>

<h2>
	استعمال أكثر من وسيط داخل <code>func.apply</code>
</h2>

<p>
	الآن صار وقت تعميم <code>‎cachingDecorator‎</code> على العالم. كنّا إلى هنا نستعملها مع الدوال التي تأخذ مُعاملًا واحدًا فقط.
</p>

<p>
	وماذا لو أردنا تخبئة التابِع <code>‎worker.slow‎</code> الذي يأخذ أكثر من مُعامل؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_25" style=""><span class="pln">let worker </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  slow</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"> max</span><span class="pun">;</span><span class="pln"> </span><span class="com">// نُعدّها عملية تستنزف المعالج</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// علينا تذكّر الاستدعاءات بنفس المُعامل هنا</span><span class="pln">
worker</span><span class="pun">.</span><span class="pln">slow </span><span class="pun">=</span><span class="pln"> cachingDecorator</span><span class="pun">(</span><span class="pln">worker</span><span class="pun">.</span><span class="pln">slow</span><span class="pun">);</span></pre>

<p>
	كنّا سابقًا نستعمل <code>‎cache.set(x, result)‎</code> (حين تعاملنا مع المُعامل الوحيد <code>‎x‎</code>) لنحفظ الناتج، ونستعمل <code>‎cache.get(x)‎</code> لنجلب الناتج. أمّا الآن فعلينا تذكّر ناتج <em>مجموعة مُعاملات</em> <code>‎(min,max)‎</code>. الخارطة <code>‎Map‎</code> لا تأخذ المفاتيح إلّا بقيمة واحدة.
</p>

<p>
	ثمّة أمامنا أكثر من حلّ:
</p>

<ol>
	<li>
		كتابة بنية بيانات جديدة تشبه الخرائط (أو استعمال واحدة من طرف ثالث) يمكن استعمالها لأكثر من أمر وتسمح لنا بتخزين أكثر من مفتاح.
	</li>
	<li>
		استعمال الخرائط المتداخلة: تصير <code>‎cache.set(min)‎</code> خارطة تُخزّن الزوجين <code>‎(max, result)‎</code>. ويمكن أن نأخذ الناتج <code>‎result‎</code> باستعمال <code>‎cache.get(min).get(max)‎</code>.
	</li>
	<li>
		دمج القيمتين في واحدة. في حالتنا هذه يمكن استعمال السلسلة النصية <code>‎"min,max"‎</code> لتكون مفتاح <code>‎Map‎</code>. ويمكن أن نقدّم للمُزخرِف <em>دالة عنونة</em> <em>Hashing</em> يمكنها صناعة قيمة من أكثر من قيمة، فيصير الأمر أسهل.
	</li>
</ol>

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

<p>
	علينا أيضًا استبدال التابِع <code>‎func.call(this, x)‎</code> بالتابِع <code>‎func.call(this, ...arguments)‎</code> كي نُمرّر كلّ المُعاملات إلى استدعاء الدالة المُغلّفة لا الأولى فقط.
</p>

<p>
	رحّب بالمُزخرف <code>‎cachingDecorator‎</code> الجديد، أكثر قوة وأناقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_27" style=""><span class="pln">let worker </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  slow</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">
    alert</span><span class="pun">(`‎</span><span class="typ">Called</span><span class="pln"> </span><span class="kwd">with</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">min</span><span class="pun">},</span><span class="pln">$</span><span class="pun">{</span><span class="pln">max</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"> max</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"> cachingDecorator</span><span class="pun">(</span><span class="pln">func</span><span class="pun">,</span><span class="pln"> hash</span><span class="pun">)</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">Map</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">
    let key </span><span class="pun">=</span><span class="pln"> hash</span><span class="pun">(</span><span class="pln">arguments</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
    </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">key</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">key</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"> func</span><span class="pun">.</span><span class="pln">call</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">arguments</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (**)</span><span class="pln">

    cache</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="pln">key</span><span class="pun">,</span><span class="pln"> result</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">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> hash</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="kwd">return</span><span class="pln"> args</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">','</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> args</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">

worker</span><span class="pun">.</span><span class="pln">slow </span><span class="pun">=</span><span class="pln"> cachingDecorator</span><span class="pun">(</span><span class="pln">worker</span><span class="pun">.</span><span class="pln">slow</span><span class="pun">,</span><span class="pln"> hash</span><span class="pun">);</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> worker</span><span class="pun">.</span><span class="pln">slow</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">// يعمل</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Again "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> worker</span><span class="pun">.</span><span class="pln">slow</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">// ‫نفس الناتج (خبّأناه)</span></pre>

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

<p>
	أمامنا تعديلان اثنان:
</p>

<ul>
	<li>
		في السطر<code>‎(*)‎</code>، نستدعي <code>‎hash‎</code> لتصنع مفتاحًا واحدًا من <code>‎arguments‎</code>. نستعمل هنا دالة «دمج» بسيطة تحوّل المُعاملان <code>‎(3, 5)‎</code> إلى المفتاح <code>‎"3,5"‎</code>. لو كانت الحالة لديك أكثر تعقيدًا، فتحتاج إلى دوال عنونة أخرى.
	</li>
	<li>
		ثمّ يستعمل <code>‎(**)‎</code> التابِع <code>‎func.call(this, ...arguments)‎</code> لتمرير السياق وكلّ المُعاملات التي استلمها الغِلاف (وليس الأول فقط) - كله إلى الدالة الأصلية.
	</li>
</ul>

<p>
	يمكننا بدل استعمال <code>‎func.call(this, ...arguments)‎</code> استغلال <code>‎func.apply(this, arguments)‎</code>.
</p>

<p>
	صياغة هذا التابِع المبني في اللغة <a href="https://wiki.hsoub.com/JavaScript/Function/apply" rel="external">func.apply</a> هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_29" style=""><span class="pln">func</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="pln">context</span><span class="pun">,</span><span class="pln"> args</span><span class="pun">)</span></pre>

<p>
	يُشغّل التابِع الدالةَ <code>‎func‎</code> بضبط <code>‎this=context‎</code> واستعمال الكائن الشبيه بالمصفوفات <code>‎args‎</code> قائمةً بالمُعطيات للدالة.
</p>

<p>
	الفارق الوحيد بين <code>‎call‎</code> و<code>‎apply‎</code> هي أنّ الأوّل يتوقّع قائمة بالمُعطيات بينما الثاني يأخذ كائنًا شبيهًا بالمصفوفات يحويها.
</p>

<p>
	أي أنّ الاستدعاءين الآتين متساويين تقريبًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_31" style=""><span class="pln">func</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="pln">context</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">args</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">apply</span><span class="pun">(</span><span class="pln">context</span><span class="pun">,</span><span class="pln"> args</span><span class="pun">);</span><span class="pln">   </span><span class="com">// ‫نفس الفكرة باستعمال apply</span></pre>

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

<ul>
	<li>
		يُتيح لنا مُعامل التوزيع <code>‎...‎</code> تمرير <em>المُتعدَّد</em> <code>‎args‎</code> قائمةً إلى <code>‎call‎</code>.
	</li>
	<li>
		لا يقبل <code>‎apply‎</code> إلّا مُعامل <code>‎args‎</code> <em>شبيه بالمصفوفات</em>.
	</li>
</ul>

<p>
	أي أنّ هذين الاستدعاءين يُكمّلان بعضهما البعض. لو توقّعنا وصول مُتعدَّد فنستعمل <code>‎call‎</code>، ولو توقّعنا شبيهًا بالمصفوفات نستعمل <code>‎apply‎</code>.
</p>

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

<p>
	يُدى تمرير كافة المُعاملات (مع السياق) من دالة إلى أخرى <em>بتمرير الاستدعاء</em>.
</p>

<p>
	إليك أبسط صوره:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_33" style=""><span class="pln">let wrapper </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"> func</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> arguments</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	حين تستدعي أيّ شيفرة خارجية <code>‎wrapper‎</code> محال أن تفرّق بين استدعائها واستدعاء الدالة الأصلية <code>‎func‎</code>.
</p>

<h2>
	استعارة التوابِع
</h2>

<p>
	أمّا الآن لنحسّن دالة العنونة قليلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_35" style=""><span class="kwd">function</span><span class="pln"> hash</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="kwd">return</span><span class="pln"> args</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">','</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> args</span><span class="pun">[</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا تعمل الدالة حاليًا إلّا على مُعاملين اثنين، وسيكون رائعًا لو أمكن أن ندمج أيّ عدد من <code>‎args‎</code>.
</p>

<p>
	أوّل حلّ نفكّر به هو استعمال التابِع <a href="https://wiki.hsoub.com/JavaScript/Array/join" rel="external">arr.join</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_37" style=""><span class="kwd">function</span><span class="pln"> hash</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="kwd">return</span><span class="pln"> args</span><span class="pun">.</span><span class="pln">join</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ولكن… للأسف فهذا لن ينفع، إذ نستدعي <code>‎hash(arguments)‎</code> بتمرير كائن المُعاملات <code>‎arguments‎</code> المُتعدَّد والشبيه بالمصفوفات… إلّا أنّه ليس بمصفوفة حقيقية.
</p>

<p>
	بذلك استدعاء <code>‎join‎</code> سيفشل كما نرى أسفله:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_39" style=""><span class="kwd">function</span><span class="pln"> hash</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">join</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫خطأ: arguments.join ليست بدالة</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

hash</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></pre>

<p>
	مع ذلك فما زال هناك طريقة سهلة لضمّ عناصر المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_41" style=""><span class="kwd">function</span><span class="pln"> hash</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">join</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="pln">arguments</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1,2</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

hash</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></pre>

<p>
	ندعو هذه الخدعة <em>باستعارة التوابِع</em>.
</p>

<p>
	فيها نأخذ (أي نستعير) تابِع الضمّ من المصفوفات العادية (<code>‎[].join‎</code>) ونستعمل <code>‎[].join.call‎</code> لتشغيله داخل سياق <code>‎arguments‎</code>.
</p>

<p>
	ولكن، لمَ تعمل أصلًا؟
</p>

<p>
	هذا بسبب بساطة الخوارزمية الداخلية للتابِع الأصيل <code>‎arr.join(glue)‎</code> في اللغة.
</p>

<p>
	أقتبس -بتصرّف خفيف جدًا- من مواصفات اللغة:
</p>

<ol>
	<li>
		لمّا أنّ <code>‎glue‎</code> هو المُعامل الأول، ولو لم تكن هناك مُعاملات فهو <code>‎","‎</code>.
	</li>
	<li>
		لمّا أنّ <code>‎result‎</code> هي سلسلة نصية فارغة.
	</li>
	<li>
		أضِف <code>‎this[0]‎</code> إلى نهاية <code>‎result‎</code>. أضِف <code>‎glue‎</code> و<code>‎this[1]‎</code>.
	</li>
	<li>
		أضِف <code>‎glue‎</code> و<code>‎this[2]‎</code>.
	</li>
	<li>
		…كرّر حتّى يتنهي ضمّ العناصر الـ <code>‎this.length‎</code>.
	</li>
	<li>
		أعِد <code>‎result‎</code>.
	</li>
</ol>

<p>
	إذًا فهو يأخذ <code>‎this‎</code> ويضمّ <code>‎this[0]‎</code> ثمّ <code>‎this[1]‎</code> وهكذا معًا. كتب المطوّرون التابِع بهذه الطريقة عمدًا ليسمح أن تكون <code>‎this‎</code> أيّ شبيه بالمصفوفات (ليست مصادفة إذ تتبع كثير من التوابِع هذه الممارسة). لهذا يعمل التابِع حين يكون <code>‎this=arguments‎</code>.
</p>

<h2>
	المزخرفات decorators‌ وخاصيات الدوال
</h2>

<p>
	استبدال الدوال أو التوابِع بأخرى مُزخرفة هو أمر آمن عادةً، ولكن باستثناء صغير: لو احتوت الدالة الأًلية على خاصيات (مثل <code>‎func.calledCount‎</code>) فلن تقدّمها الدالة المُزخرفة، إذ أنّها غِلاف على الدالة الأصلية. علينا بذلك أن نحذر في هذه الحالة.
</p>

<p>
	نأخذ المثال أعلاه مثالًا، لو احتوت الدالة <code>‎slow‎</code> أيّ خاصيات فلن يحتوي الغِلاف <code>‎cachingDecorator(slow)‎</code> عليها.
</p>

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

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

<h2>
	ملخص
</h2>

<p>
	تُعدّ <em>المزخرفات</em> أغلفة حول الدوال فتعدّل سلوكها، بينما المهمة الأساس مرهونة بالدالة نفسها.
</p>

<p>
	يمكن عدّ المُزخرِفات «مزايا» نُضيفها على الدالة، فنُضيف واحدة أو أكثر، ودون تغيير أيّ سطر في الشيفرة!
</p>

<p>
	رأينا التوابِع الآتية لنعرف كيفية إعداد المُزخرِف <code>‎cachingDecorator‎</code>:
</p>

<ul>
	<li>
		<a href="https://wiki.hsoub.com/JavaScript/Function/call" rel="external">func.call(context, arg1, arg2…)</a><code>‎</code> -- يستدعي <code>‎func‎</code> حسب السياق والمُعاملات الممرّرة.
	</li>
	<li>
		<a href="https://wiki.hsoub.com/JavaScript/Function/apply" rel="external">func.apply(context, args)</a><code>‎</code> -- يستدعي <code>‎func‎</code> حيث يُمرّر <code>‎context‎</code> بصفته <code>‎this‎</code> والكائن الشبيه بالمصفوفات <code>‎args‎</code> في قائمة المُعاملات.
	</li>
</ul>

<p>
	عادةً ما نكتب <em>تمرير الاستدعاءات</em> باستعمال <code>‎apply‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_43" style=""><span class="pln">let wrapper </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"> original</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> arguments</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	كما رأينا مثالًا عن <em>استعارة التوابِع</em> حيث أخذنا تابِعًا من كائن واستدعيناه <code>‎call‎</code> في سياق كائن آخر غيره. يشيع بين المطوّرين أخذ توابِع المصفوفات وتطبيقها على المُعاملات <code>‎arguments‎</code>. لو أردت بديلًا لذلك فاستعمل كائن المُعاملات البقية إذ هو مصفوفة حقيقية.
</p>

<p>
	ستجد في رحلتك المحفوفة بالمخاطر مُزخرِفات عديدة. حاوِل التمرّس عليها بحلّ تمارين هذا الفصل.
</p>

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

<h3>
	مزخرف تجسس
</h3>

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

<p>
	أنشِئ المُزخرِف <code>‎spy(func)‎</code> ليُعيد غِلافًا يحفظ كلّ استدعاءات تلك الدالة في خاصية <code>‎calls‎</code> داخله.
</p>

<p>
	احفظ كلّ استدعاء على أنّه مصفوفة من الوُسطاء.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_45" style=""><span class="kwd">function</span><span class="pln"> work</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"> b </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫ليست work إلّا دالة أو تابِعًا لسنا نعرف أصله</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

work </span><span class="pun">=</span><span class="pln"> spy</span><span class="pun">(</span><span class="pln">work</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">

work</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">// 3</span><span class="pln">
work</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="com">// 9</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let args of work</span><span class="pun">.</span><span class="pln">calls</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">'call:'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> args</span><span class="pun">.</span><span class="pln">join</span><span class="pun">()</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// "call:1,2", "call:4,5"</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ملاحظة: نستفيد من هذا المُزخرِف أحيانًا لاختبار الوحدات. يمكن عدّ <code>‎sinon.spy‎</code> في المكتبة <a href="http://sinonjs.org/" rel="external nofollow">Sinon.JS</a> صورةً متقدّمةً عنه.
</p>

<h4>
	الحل
</h4>

<p>
	سيُخزّن الغِلاف الذي أعادته <code>spy(f)‎</code> كلّ الوُسطاء، بعدها يستعمل <code>f.apply</code> لتمرير الاستدعاء. …..
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4399_7" style=""><span class="kwd">function</span><span class="pln"> spy</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">function</span><span class="pln"> wrapper</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">// ‫استعملنا arg... بدلًا من arguments للحصول على مصفوفة حقيقية في wrapper.calls</span><span class="pln">
    wrapper</span><span class="pun">.</span><span class="pln">calls</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">args</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> func</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="kwd">this</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">

  wrapper</span><span class="pun">.</span><span class="pln">calls </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"> wrapper</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	مزخرف تأخير
</h3>

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

<p>
	أنشِئ المُزخرف <code>‎delay(f, ms)‎</code> ليُؤخّر كلّ استدعاء من <code>‎f‎</code> بمقدار <code>‎ms‎</code> مليثانية.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_47" style=""><span class="kwd">function</span><span class="pln"> f</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">
  alert</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="com">// أنشِئ الغِلافات</span><span class="pln">
let f1000 </span><span class="pun">=</span><span class="pln"> delay</span><span class="pun">(</span><span class="pln">f</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
let f1500 </span><span class="pun">=</span><span class="pln"> delay</span><span class="pun">(</span><span class="pln">f</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1500</span><span class="pun">);</span><span class="pln">

f1000</span><span class="pun">(</span><span class="str">"test"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫يعرض «test» بعد 1000 مليثانية</span><span class="pln">
f1500</span><span class="pun">(</span><span class="str">"test"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫يعرض «test» بعد 1500 مليثانية</span></pre>

<p>
	أي أنّ المُزخرِف <code>‎delay(f, ms)‎</code> يُعيد نسخة عن <code>‎f‎</code> «تأجّلت <code>‎ms‎</code>».
</p>

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

<h4>
	الحل
</h4>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_49" style=""><span class="kwd">function</span><span class="pln"> delay</span><span class="pun">(</span><span class="pln">f</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="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">
    setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> arguments</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="pun">}</span><span class="pln">

let f1000 </span><span class="pun">=</span><span class="pln"> delay</span><span class="pun">(</span><span class="pln">alert</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">

f1000</span><span class="pun">(</span><span class="str">"test"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫يعرض test بعد 1000 مليثانية</span></pre>

<p>
	لاحظ بأنّا استعملنا الدالة السهمية هنا. كما نعلم فالدوال السهمية لا تملك لا <code>‎this‎</code> ولا <code>‎arguments‎</code>، لذا يأخذ <code>‎f.apply(this, arguments)‎</code> كِلا <code>‎this‎</code> و<code>‎arguments‎</code> من الغِلاف.
</p>

<p>
	لو مرّرنا دالة عادية فسيستدعيها <code>‎setTimeout‎</code> بدون المُعاملات ويضبط <code>‎this=window‎</code> (باعتبار أنّا في بيئة المتصفّح).
</p>

<p>
	مع ذلك يمكننا تمرير قيمة <code>‎this‎</code> الصحيحة باستعمال متغيّر وسيط ولكنّ ذلك سيكون تعبًا لا داعٍ له:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_51" style=""><span class="kwd">function</span><span class="pln"> delay</span><span class="pun">(</span><span class="pln">f</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="kwd">return</span><span class="pln"> </span><span class="kwd">function</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">
    let savedThis </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln"> </span><span class="com">// خزّنه في متغير وسيط</span><span class="pln">
    setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      f</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="pln">savedThis</span><span class="pun">,</span><span class="pln"> args</span><span class="pun">);</span><span class="pln"> </span><span class="com">// استعمل الوسيط هنا</span><span class="pln">
    </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="pun">}</span></pre>

<h3>
	مزخرف إزالة ارتداد
</h3>

<p>
	اصنع المُزخرِف <code>‎debounce(f, ms)‎</code> ليُعيد غِلافًا يُمرّر الاستدعاء إلى <code>‎f‎</code> مرّة واحدة كلّ <code>‎ms‎</code> مليثانية.
</p>

<p>
	بعبارة أخرى: حين ندعو الدالة «بأنّ ارتدادها أُزيل» <em>Debounce</em> فهي تضمن لنا بأنّ الاستدعاءات التي ستحدث في أقلّ من <code>‎ms‎</code> مليثانية بعد الاستدعاء السابق - ستُهمل.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="122725" data-ratio="36.73" data-unique="5tqxnafu0" width="501" alt="1.jpg" src="https://academy.hsoub.com/uploads/monthly_2023_04/1.jpg.e2f59a59516e5699e1973d8b0eb6b078.jpg">
</p>

<p>
	إليك مثال (مأخوذ من مكتبة <a href="https://lodash.com/docs/4.17.15#debounce" rel="external nofollow">Lodash</a><span class="ipsEmoji">?</span>
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4399_10" style=""><span class="kwd">let</span><span class="pln"> f </span><span class="pun">=</span><span class="pln"> _</span><span class="pun">.</span><span class="pln">debounce</span><span class="pun">(</span><span class="pln">alert</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">

f</span><span class="pun">(</span><span class="str">"a"</span><span class="pun">);</span><span class="pln">
setTimeout</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"> f</span><span class="pun">(</span><span class="str">"b"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">200</span><span class="pun">);</span><span class="pln">
setTimeout</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"> f</span><span class="pun">(</span><span class="str">"c"</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">// alert("c") تنتظر 1000 م.ث بعد آخر استدعاء ثم تُنفذ</span></pre>

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

<p>
	إن فكرت بالحل، قبل النظر للشيفرة التالية، فهو عبارة عن بضعة سطور!
</p>

<h3>
	الحل
</h3>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4399_12" style=""><span class="kwd">function</span><span class="pln"> debounce</span><span class="pun">(</span><span class="pln">func</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="kwd">let</span><span class="pln"> timeout</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">
    clearTimeout</span><span class="pun">(</span><span class="pln">timeout</span><span class="pun">);</span><span class="pln">
    timeout </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> func</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> arguments</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="pun">}</span></pre>

<p>
	استدعاء ‎debounce‎ يُعيد غِلافًا. عند استدعائها، تجدول الدالة الأصلية بعد عدد الثواني المحدد وتمسح أي استدعاء سابق مُجدول.
</p>

<h3>
	مزخرف خنق
</h3>

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

<p>
	أنشِئ مُزخرِف «الخنق/throttle» ‏<code>‎throttle(f, ms)‎</code> ليُعيد غِلافًا يُمرّر الاستدعاء إلى <code>‎f‎</code> مرّة كلّ <code>‎ms‎</code> مليثانية. والاستدعاءات التي تحدث في فترة «الراحة» تُهمل.
</p>

<p>
	<strong>الفرق بين هذه وبين <code>‎debounce‎</code> هي أنّه لو كان الاستدعاء المُهمل هو آخر الاستدعاءات أثناء فترة الراحة، فسيعمل متى انتهت تلك الفترة.</strong>
</p>

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

<p>
	<strong>لنقل مثلًا أنّا نريد تعقّب تحرّك الفأرة.</strong>
</p>

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

<p>
	<strong>نريد تحديث بعض المعلومات في صفحة الوِب أثناء حركة المؤشّر.</strong>
</p>

<p>
	…ولكن تحديث الدالة <code>‎update()‎</code> عملية ثقيلة ولا تنفع لكلّ حركة فأرة صغيرة. كما وليس منطقيًا أصلًا التحديث أكثر من مرّة كلّ 100 مليثانية.
</p>

<p>
	لذا نُغلّف الدالة في مُزخرف: نستعمل <code>‎throttle(update, 100)‎</code> على أنّها دالة التشغيل كلّما تحرّكت الفأرة بدلًا من الدالة <code>‎update()‎</code> الأصلية. سيُستدعى المُزخرِف كثيرًا صحيح، ولكنّها لن يمرّر الاستدعاءات هذه إلى <code>‎update()‎</code> إلّا مرّة كلّ 100 مليثانية.
</p>

<p>
	هكذا سيظهر للمستخدم:
</p>

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

<p>
	مثال عن الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_57" style=""><span class="kwd">function</span><span class="pln"> f</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">
  console</span><span class="pun">.</span><span class="pln">log</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="com">// تمرّر f1000 الاستدعاءات إلى f مرّة كلّ 1000 مليثانية كحدّ أقصى</span><span class="pln">
let f1000 </span><span class="pun">=</span><span class="pln"> throttle</span><span class="pun">(</span><span class="pln">f</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">

f1000</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">
f1000</span><span class="pun">(</span><span class="lit">2</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (مخنوقة، لم تمض 1000 مليثانية بعد)</span><span class="pln">
f1000</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (مخنوقة، لم تمض 1000 مليثانية بعد)</span><span class="pln">

</span><span class="com">// ‫حين تمضي 1000 مليثانية...</span><span class="pln">
</span><span class="com">// ‫...تطبع 3، إذ القيمة 2 الوسطية أُهملت</span></pre>

<p>
	ملاحظة: يجب تمرير المُعاملات والسياق <code>‎this‎</code> المُمرّرة إلى <code>‎f1000‎</code>- تمريرها إلى <code>‎f‎</code> الأصلية.
</p>

<h3>
	الحل
</h3>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2803_59" style=""><span class="kwd">function</span><span class="pln"> throttle</span><span class="pun">(</span><span class="pln">func</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">

  let isThrottled </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    savedArgs</span><span class="pun">,</span><span class="pln">
    savedThis</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">function</span><span class="pln"> wrapper</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">isThrottled</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">
      savedArgs </span><span class="pun">=</span><span class="pln"> arguments</span><span class="pun">;</span><span class="pln">
      savedThis </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">return</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">apply</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> arguments</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (1)</span><span class="pln">

    isThrottled </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

    setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      isThrottled </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">// (3)</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">savedArgs</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        wrapper</span><span class="pun">.</span><span class="pln">apply</span><span class="pun">(</span><span class="pln">savedThis</span><span class="pun">,</span><span class="pln"> savedArgs</span><span class="pun">);</span><span class="pln">
        savedArgs </span><span class="pun">=</span><span class="pln"> savedThis </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="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="kwd">return</span><span class="pln"> wrapper</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُعيد استدعاء <code>‎throttle(func, ms)‎</code> الغِلاف <code>‎wrapper‎</code>.
</p>

<ol>
	<li>
		أثناء الاستدعاء الأول، يُشغّل <code>‎wrapper‎</code> ببساطة الدالة <code>‎func‎</code> ويضبط حالة الراحة (<code>‎isThrottled = true‎</code>).
	</li>
	<li>
		في هذه الحالة نحفظ كلّ الاستدعاءات في <code>‎savedArgs/savedThis‎</code>. لاحظ بأنّ السياق والوُسطاء مهمّان ويجب حفظهما كلاهما، فنحتاجهما معًا لنُعيد ذلك الاستدعاء كما كان ونستدعيه حقًا.
	</li>
	<li>
		بعد مرور <code>‎ms‎</code> مليثانية، يعمل <code>‎setTimeout‎</code>، بهذا تُزال حالة الراحة (<code>‎isThrottled = false‎</code>) ولو كانت هناك استدعاءات مُهملة، نُنفّذ <code>‎wrapper‎</code> بآخر ما حفظنا من وُسطاء وسياق.
	</li>
</ol>

<p>
	لا نشغّل في الخطوة الثالثة <code>‎func‎</code> بل <code>‎wrapper‎</code> إذ نريد تنفيذ <code>‎func‎</code> إضافةً إلى دخول حالة الراحة ثانيةً وضبط المؤقّت لتصفيرها.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/call-apply-decorators" rel="external nofollow">Decorators and forwarding, call/apply</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">878</guid><pubDate>Thu, 07 May 2020 18:07:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62C;&#x62F;&#x648;&#x644;&#x629;: &#x627;&#x644;&#x645;&#x647;&#x644;&#x629; setTimeout &#x648;&#x627;&#x644;&#x641;&#x62A;&#x631;&#x629; setInterval &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AC%D8%AF%D9%88%D9%84%D8%A9-%D8%A7%D9%84%D9%85%D9%87%D9%84%D8%A9-settimeout-%D9%88%D8%A7%D9%84%D9%81%D8%AA%D8%B1%D8%A9-setinterval-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r877/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_04/51.jpg.14c297ea3fd43771a4e0b4bdcdf62163.jpg" /></p>

<p>
	وأنت تكتب الشيفرة، ستقول في نفسك «أريد تشغيل هذه الدالة بعد قليل وليس الآن الآن. هذا ما نسمّيه "بجدولة الاستدعاءات" (scheduling a call).
</p>

<p>
	إليك تابِعين اثنين لهذه الجدولة:
</p>

<ul>
<li>
		يتيح لك <code>‎setTimeout‎</code> تشغيل الدالة مرّة واحدة بعد فترة من الزمن.
	</li>
	<li>
		يتيح لك <code>‎setInterval‎</code> تشغيل الدالة تكراريًا يبدأ ذلك بعد فترة من الزمن ويتكرّر كلّ فترة حسب تلك الفترة التي حدّدتها.
	</li>
</ul>
<p>
	صحيح أنّ هذين التابِعين ليسا في مواصفة لغة جافاسكربت إلّا أنّ أغلب البيئات فيها مُجدوِل داخلي يقدّمهما لنا. وللدقّة، فكلّ المتصّفحات كما وNode.js تدعمهما.
</p>

<h2>
	تابع تحديد المهلة setTimeout
</h2>

<p>
	الصياغة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_7" style="">
<span class="pln">let timerId </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(</span><span class="pln">func</span><span class="pun">|</span><span class="pln">code</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="pln">delay</span><span class="pun">],</span><span class="pln"> </span><span class="pun">[</span><span class="pln">arg1</span><span class="pun">],</span><span class="pln"> </span><span class="pun">[</span><span class="pln">arg2</span><span class="pun">],</span><span class="pln"> </span><span class="pun">...)</span></pre>

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

<ul>
<li>
		<code>func|code</code>: ما يجب تنفيذه أكان دالة أو سلسلة نصية فيها شيفرة. عادةً هي دالة ولكن كعادة الأسباب التاريخية (أيضًا) يمكن تمرير سلسلة نصية فيها شيفرة، ولكنّ ذلك ليس بالأمر المستحسن.
	</li>
	<li>
		<code>delay</code>: التأخير قبل بدء التنفيذ بالمليثانية (1000 مليثانية = ثانية واحدة). مبدئيًا يساوي 0.
	</li>
	<li>
		<code>arg1</code>‎, ‎<code>arg2</code>…: وُسطاء الدالة (ليست مدعومة في IE9-‎)
	</li>
</ul>
<p>
	إليك هذه الشيفرة التي تستدعي <code>‎sayHi()‎</code> بعد ثانيةً واحدة:
</p>

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

setTimeout</span><span class="pun">(</span><span class="pln">sayHi</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_11" style="">
<span class="kwd">function</span><span class="pln"> sayHi</span><span class="pun">(</span><span class="pln">phrase</span><span class="pun">,</span><span class="pln"> who</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="str">', '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> who </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

setTimeout</span><span class="pun">(</span><span class="pln">sayHi</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hello"</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">// Hello, John</span></pre>

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

<p>
	أي أنّ هذا سيعمل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_13" style="">
<span class="pln">setTimeout</span><span class="pun">(</span><span class="str">"alert('Hello')"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span></pre>

<p>
	ولكن استعمال السلاسل النصية غير مستحسن. استعمل الدوال السهمية بدلًا عنها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_15" style="">
<span class="pln">setTimeout</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="str">'Hello'</span><span class="pun">),</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_17" style="">
<span class="com">// هذا خطأ!</span><span class="pln">
setTimeout</span><span class="pun">(</span><span class="pln">sayHi</span><span class="pun">(),</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span></pre>

<p>
	لن يعمل ذلك إذ يتوقّع <code>‎setTimeout‎</code> إشارة إلى الدالة، بينما هنا <code>‎sayHi()‎</code> يشغّل الدالة و<em>ناتج التنفيذ</em> هو الذي يُمرّر إلى <code>‎setTimeout‎</code>. في حالتنا ناتج <code>‎sayHi()‎</code> ليس معرّفًا <code>‎undefined‎</code> (إذ لا تُعيد الدالة شيئًا)، ويعني ذلك أنّ عملنا ذهب سدًى ولم نُجدول أي شيء.
</p>

<h3>
	الإلغاء باستعمال <code>clearTimeout</code>
</h3>

<p>
	نستلمُ حين نستدعي <code>‎setTimeout‎</code> «هويّةَ المؤقّت» <code>‎timerId‎</code> ويمكن استعمالها لإلغاء عملية التنفيذ.
</p>

<p>
	صياغة الإلغاء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_19" style="">
<span class="pln">let timerId </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(...);</span><span class="pln">
clearTimeout</span><span class="pun">(</span><span class="pln">timerId</span><span class="pun">);</span></pre>

<p>
	في الشيفرة أسفله نُجدول الدالة ثمّ نُلغيها (غيّرنا الخطّة العبقرية)، بهذا لا يحدث شيء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_21" style="">
<span class="pln">let timerId </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="str">"never happens"</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">timerId</span><span class="pun">);</span><span class="pln"> </span><span class="com">// هويّة المؤقّت</span><span class="pln">

clearTimeout</span><span class="pun">(</span><span class="pln">timerId</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">timerId</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫ذات الهويّة (لا تصير null بعد الإلغاء)</span></pre>

<p>
	يمكن أن نرى من ناتج التابِع <code>‎alert‎</code> أنّ هويّة المؤقّت (في المتصفّحات) هي عدد. يمكن أن تكون في البيئات الأخرى أيّ شيء آخر. فمثلًا في Node.js نستلم كائن مؤقّت فيه توابِع أخرى.
</p>

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

<p>
	يمكنك مراجعة مواصفة HTML5 للمؤقّتات (داخل المتصفّحات) في <a href="https://www.w3.org/TR/html5/webappapis.html#timers" rel="external nofollow">فصل المؤقّتات</a>.
</p>

<h2>
	setInterval
</h2>

<p>
	صياغة التابِع <code>‎setInterval‎</code> هي ذات <code>‎setTimeout‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_23" style="">
<span class="pln">let timerId </span><span class="pun">=</span><span class="pln"> setInterval</span><span class="pun">(</span><span class="pln">func</span><span class="pun">|</span><span class="pln">code</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="pln">delay</span><span class="pun">],</span><span class="pln"> </span><span class="pun">[</span><span class="pln">arg1</span><span class="pun">],</span><span class="pln"> </span><span class="pun">[</span><span class="pln">arg2</span><span class="pun">],</span><span class="pln"> </span><span class="pun">...)</span></pre>

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

<p>
	يمكن أن نستدعي <code>‎clearInterval(timerId)‎</code> لنُوقف الاستدعاءات اللاحقة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_26" style="">
<span class="com">// نكرّر التنفيذ بفترة تساوي ثانيتين</span><span class="pln">
let timerId </span><span class="pun">=</span><span class="pln"> setInterval</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="str">'tick'</span><span class="pun">),</span><span class="pln"> </span><span class="lit">2000</span><span class="pun">);</span><span class="pln">

</span><span class="com">// وبعد خمس ثوان نُوقف الجدولة</span><span class="pln">
setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> clearInterval</span><span class="pun">(</span><span class="pln">timerId</span><span class="pun">);</span><span class="pln"> alert</span><span class="pun">(</span><span class="str">'stop'</span><span class="pun">);</span><span class="pln"> </span><span class="pun">},</span><span class="pln"> </span><span class="lit">5000</span><span class="pun">);</span></pre>

<p>
	<strong>الوقت لا يتوقّف حين تظهر مُنبثقة <code>‎alert‎</code></strong> تُواصل عقارب ساعة المؤقّت الداخلي (في أغلب المتصفّحات بما فيها كروم وفَيَرفُكس) بالمضيّ حتّى حين عرض <code>‎alert/confirm/prompt‎</code>.
</p>

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

<h2>
	تداخل setTimeout
</h2>

<p>
	لو أردنا تشغيل أمر كلّ فترة، فهناك طريقتين اثنتين.
</p>

<p>
	الأولى هي <code>‎setInterval‎</code>. والثانية هي <code>‎setTimeout‎</code> متداخلة هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_28" style="">
<span class="com">/** بدل كتابة:
let timerId = setInterval(() =&gt; alert('tick'), 2000);
*/</span><span class="pln">

let timerId </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> tick</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">'tick'</span><span class="pun">);</span><span class="pln">
  timerId </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(</span><span class="pln">tick</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2000</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="lit">2000</span><span class="pun">);</span></pre>

<p>
	تابِع <code>‎setTimeout‎</code> أعلاه يُجدول الاستدعاء التالي ليحدث بعد نهاية الأول (لاحظ <code>‎(*)‎</code>).
</p>

<p>
	كتابة توابِع <code>‎setTimeout‎</code> متداخلة يعطينا شيفرة مطواعة أكثر من <code>‎setInterval‎</code>. بهذه الطريقة يمكن تغيير جدولة الاستدعاء التالي حسب ناتج الحالي.
</p>

<p>
	فمثلًا علينا كتابة خدمة تُرسل طلب بيانات إلى الخادوم كلّ خمس ثوان، ولكن لو كان الخادوم مُثقلًا بالعمليات فيجب أن تزداد الفترة إلى 10 فَـ 20 فَـ 40 ثانية وهكذا…
</p>

<p>
	إليك فكرة عن الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_30" style="">
<span class="pln">let delay </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5000</span><span class="pun">;</span><span class="pln">

let timerId </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> request</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">if</span><span class="pln"> </span><span class="pun">(لو</span><span class="pln"> </span><span class="pun">فشل</span><span class="pln"> </span><span class="pun">الطلب</span><span class="pln"> </span><span class="pun">لوجود</span><span class="pln"> </span><span class="pun">ضغط</span><span class="pln"> </span><span class="pun">على</span><span class="pln"> </span><span class="pun">الخادوم)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// نزيد الفترة حتّى الطلب التالي</span><span class="pln">
    delay </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">

  timerId </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">);</span><span class="pln">

</span><span class="pun">},</span><span class="pln"> delay</span><span class="pun">);</span></pre>

<p>
	ولو كانت الدوال التي نُجدولها ثقيلة على المعالج فيمكن أن نقيس الزمن الذي أخذتها عملية التنفيذ الحالية ونؤجّل أو نقدّم الاستدعاء التالي.
</p>

<p>
	<strong>يتيح لنا تداخل التوابِع <code>‎setTimeout‎</code> بضبط الفترة بين عمليات التنفيذ بدقّة أعلى ممّا تقدّمه <code>‎setInterval‎</code>.</strong>
</p>

<p>
	لنرى الفرق بين الشيفرتين أسفله. الأولى تستعمل <code>‎setInterval‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_32" style="">
<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">
setInterval</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  func</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="lit">100</span><span class="pun">);</span></pre>

<p>
	الثانية تستعمل <code>‎setTimeout‎</code> متداخلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_34" style="">
<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">
setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> run</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">i</span><span class="pun">++);</span><span class="pln">
  setTimeout</span><span class="pun">(</span><span class="pln">run</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></pre>

<p>
	سيُشغّل المُجدول الداخلي <code>‎func(i++)‎</code> كلّ 100 مليثانية حسب <code>‎setInterval‎</code>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="42603" href="https://academy.hsoub.com/uploads/monthly_2020_04/setinterval-interval.png.2fccb15407803e6bd5f68a52bb8bc5c1.png" rel=""><img alt="setinterval-interval.png" class="ipsImage ipsImage_thumbnailed" data-fileid="42603" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/setinterval-interval.png.2fccb15407803e6bd5f68a52bb8bc5c1.png"></a>
</p>

<p>
	هل لاحظت ذلك؟
</p>

<p>
	<strong>التأخير الفعلي بين استدعاءات <code>‎func‎</code> التي ينفّذها <code>‎setInterval‎</code> أقل مما هي عليه في الشيفرة!</strong>
</p>

<p>
	هذا طبيعي إذ أنّ الوقت الذي يأخذه تنفيذ <code>‎func‎</code> يستهلك بعضًا من تلك الفترة أيضًا.
</p>

<p>
	يمكن أيضًا بأن يصير تنفيذ <code>‎func‎</code> أكبر ممّا توقعناه على حين غرّة ويأخذ وقتًا أطول من 100 مليثانية.
</p>

<p>
	في هذه الحال ينتظر المحرّك انتهاء <code>‎func‎</code> ثمّ يرى المُجدول: لو انقضى الوقت يشغّل الدالة <em>مباشرةً</em>.
</p>

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

<p>
	وإليك صورة <code>‎setTimeout‎</code> المتداخلة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="42604" href="https://academy.hsoub.com/uploads/monthly_2020_04/settimeout-interval.png.7471c7bda043a37e31a8c0676a315c5a.png" rel=""><img alt="settimeout-interval.png" class="ipsImage ipsImage_thumbnailed" data-fileid="42604" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_04/settimeout-interval.png.7471c7bda043a37e31a8c0676a315c5a.png"></a>
</p>

<p>
	<strong>تضمن <code>‎setTimeout‎</code> المتداخلة لنا التأخير الثابت (100 مليثانية في حالتنا).</strong>
</p>

<p>
	ذلك لأنّ الاستدعاء التالي لا يُجدول إلا بعد انتهاء السابق.
</p>

<p>
	<strong>كنس المهملات وردود نداء التابِعين setInterval و setTimeout</strong> تُنشأ إشارة داخلية إلى الدالة (وتُحفظ في المُجدول) متى مرّرتها إلى إلى <code>‎setInterval/setTimeout‎</code>، وهذا يمنع كنس الدالة على أنّها مهملات، حتّى لو لم تكن هناك إشارات إليها.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_36" style="">
<span class="com">// ‫تبقى الدالة في الذاكرة حتّى يُستدعى `‎clearInterval‎`.</span><span class="pln">
setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{...},</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span></pre>

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

<h2>
	جدولة setTimeout بتأخير صفر
</h2>

<p>
	إليك الحالة الخاصة: <code>‎setTimeout(func, 0)‎</code> أو <code>‎setTimeout(func)‎</code>.
</p>

<p>
	يُجدول هذا التابِع ليحدث تنفيذ <code>‎func‎</code> بأسرع ما يمكن، إلّا أن المُجدول لن يشغّلها إلا بعد انتهاء السكربت الذي يعمل حاليًا.
</p>

<p>
	أي أنّ الدالة تُجدول لأن تعمل «مباشرةً بعد» السكربت الحالي.
</p>

<p>
	فمثلًا تكتب هذه الشيفرة "Hello" ثم مباشرة "World":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_38" style="">
<span class="pln">setTimeout</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="str">"World"</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>
	يعني السطر الأوّل «ضع الاستدعاء في التقويم بعد 0 مليثانية»، إلّا أنّ المُجدول لا «يفحص تقويمه» إلّا بعد انتهاء السكربت الحالي، بهذا تصير <code>‎"Hello"‎</code> أولًا وبعدها تأتي <code>‎"World"‎</code>.
</p>

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

<p>
	<strong>في الواقع، فالتأخير الصفر هذا ليس صفرًا (في المتصفّحات)</strong> تحدّ المتصفّحات من التأخير بين تشغيل المؤقّتات المتداخلة. تقول <a href="https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers" rel="external nofollow">مواصفة HTML5</a>: «بعد المؤقّتات المتداخلة الخمسة الأولى، تُجبر الفترة لتكون أربع مليثوان على الأقل.».
</p>

<p>
	لنرى ما يعني ذلك بهذا المثال أسفله. يُعيد استدعاء <code>‎setTimeout‎</code> جدولة نفسه بمدّة تأخير تساوي صفر، ويتذكّر كل استدعاء الوقت الفعلي بينه وبين آخر استدعاء في مصفوفة <code>‎times‎</code>. ولكن، ما هي التأخيرات الفعلية؟ لنرى بأعيننا:
</p>

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

setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> run</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  times</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</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="com">// نحفظ التأخير من آخر استدعاء</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">start </span><span class="pun">+</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">&lt;</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"> alert</span><span class="pun">(</span><span class="pln">times</span><span class="pun">);</span><span class="pln"> </span><span class="com">// نعرض التأخيرات بعد 100 مليثانية</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> setTimeout</span><span class="pun">(</span><span class="pln">run</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="com">// 1,1,1,1,9,15,20,24,30,35,40,45,50,55,59,64,70,75,80,85,90,95,100</span></pre>

<p>
	تعمل المؤقّتات الأولى مباشرةً (كما تقول المواصفة)، وبعدها نرى <code>‎9, 15, 20, 24...‎</code>. تلك الأربع مليثوان الإضافية هي التأخير المفروض بين الاستدعاءات.
</p>

<p>
	حتّى مع <code>‎setInterval‎</code> بدل <code>‎setTimeout‎</code>، ذات الأمر: تعمل الدالة <code>‎setInterval(f)‎</code> أوّل <code>‎f‎</code> مرّة بمدّة تأخير صفر، وبعدها تزيد أربع مليثوان لباقي الاستدعاءات.
</p>

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

<p>
	بينما مع نسخة الخواديم من جافاسكربت فهذا الحدّ ليس له وجود، وهناك أيضًا طُرق أخرى لبدء المهام التزامنية مباشرةً، مثل <a href="https://wiki.hsoub.com/Node.js/timers#setImmediate.28callback.5B.2C_%E2%80%A6args.5D.29.E2.80.8E" rel="external">setImmediate</a> للغة Node.js، هذا قلنا بأنّ هذا يخصّ المتصفّحات فقط.
</p>

<h2>
	ملخص
</h2>

<ul>
<li>
		يتيح لنا التابِعان <code>‎setTimeout(func, delay, ...args)‎</code> و<code>‎setInterval(func, delay, ...args)‎</code> تشيل الدالة <code>‎func‎</code> مرّة أو كلّ فترة حسب كذا مليثانية (<code>‎delay‎</code>).
	</li>
	<li>
		لإلغاء التنفيذ علينا استدعاء <code>‎clearTimeout/clearInterval‎</code> بالقيمة التي أعاداها <code>‎setTimeout/setInterval‎</code>.
	</li>
	<li>
		يُعدّ استدعاء الدوال <code>‎setTimeout‎</code> تداخليًا خيارًا أفضل من <code>‎setInterval‎</code> إذ يُتيح لنا ضبط الوقت <em>بين</em> كلّ عملية استدعاء بدقّة.
	</li>
	<li>
		الجدولة بضبط التأخير على الصفر باستعمال <code>‎setTimeout(func, 0)‎</code> (كما واستعمال <code>‎setTimeout(func)‎</code>) يكون حين نريدها «بأقصى سرعة ممكنة، متى انتهى السكربت الحالي».
	</li>
	<li>
		يَحدّ المتصفّح من أدنى تأخير بعد استدعاء <code>‎setTimeout‎</code> أو <code>‎setInterval‎</code> المتداخل الخامس (أو أكثر) - يَحدّه إلى 4 مليثوان، وهذا لأسباب تاريخية
	</li>
</ul>
<p>
	لاحظ بأنّ توابِع الجدولة لا <em>تضمن</em> التأخير كما هو حرفيًا.
</p>

<p>
	فمثلًا يمكن أن تكون مؤقّتات المتصفّحات أبطأ لأسباب عديدة:
</p>

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

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

<h3>
	اكتب الناتج كل ثانية
</h3>

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

<p>
	اكتب الدالة <code>‎printNumbers(from, to)‎</code> لتكتب عددًا كلّ ثانية بدءًا بِـ <code>‎from‎</code> وانتهاءً بِـ <code>‎to‎</code>.
</p>

<p>
	اصنع نسختين من الحل.
</p>

<ol>
<li>
		واحدةً باستعمال <code>‎setInterval‎</code>.
	</li>
	<li>
		واحدةً باستعمال <code>‎setTimeout‎</code> متداخلة.
	</li>
</ol>
<h4>
	الحل
</h4>

<p>
	باستعمال <code>‎setInterval‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_42" style="">
<span class="kwd">function</span><span class="pln"> printNumbers</span><span class="pun">(</span><span class="pln">from</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">
  let current </span><span class="pun">=</span><span class="pln"> from</span><span class="pun">;</span><span class="pln">

  let timerId </span><span class="pun">=</span><span class="pln"> setInterval</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">current</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">current </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">
      clearInterval</span><span class="pun">(</span><span class="pln">timerId</span><span class="pun">);</span><span class="pln">
    </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="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">
printNumbers</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span></pre>

<p>
	باستعمال <code>‎setTimeout‎</code> متداخلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_44" style="">
<span class="kwd">function</span><span class="pln"> printNumbers</span><span class="pun">(</span><span class="pln">from</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">
  let current </span><span class="pun">=</span><span class="pln"> from</span><span class="pun">;</span><span class="pln">

  setTimeout</span><span class="pun">(</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">
    alert</span><span class="pun">(</span><span class="pln">current</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">current </span><span class="pun">&lt;</span><span class="pln"> to</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      setTimeout</span><span class="pun">(</span><span class="pln">go</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">
    current</span><span class="pun">++;</span><span class="pln">
  </span><span class="pun">},</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// ‫الاستعمال:</span><span class="pln">
printNumbers</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span></pre>

<p>
	لاحظ كلا الحلّين: هناك تأخير أولي قبل أول عملية كتابة إذ تُستدعى الدالة بعد <code>‎1000ms‎</code> في أوّل مرة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5576_46" style="">
<span class="kwd">function</span><span class="pln"> printNumbers</span><span class="pun">(</span><span class="pln">from</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">
  let current </span><span class="pun">=</span><span class="pln"> from</span><span class="pun">;</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">
    alert</span><span class="pun">(</span><span class="pln">current</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">current </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">
      clearInterval</span><span class="pun">(</span><span class="pln">timerId</span><span class="pun">);</span><span class="pln">
    </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">

  go</span><span class="pun">();</span><span class="pln"> </span><span class="com">// هنا</span><span class="pln">
  let timerId </span><span class="pun">=</span><span class="pln"> setInterval</span><span class="pun">(</span><span class="pln">go</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">

printNumbers</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span></pre>

<h3>
	ماذا سيعرض setTimeout؟
</h3>

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

<p>
	جدول أحدهم في الشيفرة أسفله استدعاء <code>‎setTimeout‎</code>، وثمّ كتب عملية حسابية ثقيلة لتعمل (وهي تأخذ أكثر من 100 مليثانية حتى تنتهي).
</p>

<p>
	متى ستعمل الدالة المُجدولة؟
</p>

<ol>
<li>
		بعد الحلقة؟
	</li>
	<li>
		قبل الحلقة؟
	</li>
	<li>
		في بداية الحلقة؟
	</li>
</ol>
<p>
	ما ناتج <code>‎alert‎</code>؟
</p>

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

setTimeout</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">i</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">// ?</span><span class="pln">

</span><span class="com">// عُدّ بأنّ الوقت اللازم لتنفيذ هذه الدالة يفوق 100 مليثانية</span><span class="pln">
</span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">100000000</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">
  i</span><span class="pun">++;</span><span class="pln"> 
</span><span class="pun">}</span></pre>

<h4>
	الحل
</h4>

<p>
	لن يُشغّل أيّ تابِع <code>‎setTimeout‎</code> إلا بعدما تنتهي الشيفرة الحالية.
</p>

<p>
	ستكون قيمة <code>‎i‎</code> هي القيمة الأخيرة: <code>‎100000000‎</code>.
</p>

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

setTimeout</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">i</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">// 100000000</span><span class="pln">

</span><span class="com">// عُدّ بأنّ الوقت اللازم لتنفيذ هذه الدالة يفوق 100 مليثانية</span><span class="pln">
</span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">100000000</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">
  i</span><span class="pun">++;</span><span class="pln"> 
</span><span class="pun">}</span></pre>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/settimeout-setinterval" rel="external nofollow">Scheduling: setTimeout and setInterval</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">877</guid><pubDate>Fri, 17 Apr 2020 05:48:22 +0000</pubDate></item><item><title>&#x635;&#x64A;&#x627;&#x63A;&#x629; &#x627;&#x644;&#x62F;&#x627;&#x644;&#x629; &#x627;&#x644;&#x62C;&#x62F;&#x64A;&#x62F;&#x629; new Function &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%B5%D9%8A%D8%A7%D8%BA%D8%A9-%D8%A7%D9%84%D8%AF%D8%A7%D9%84%D8%A9-%D8%A7%D9%84%D8%AC%D8%AF%D9%8A%D8%AF%D8%A9-new-function-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r876/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_04/50.jpg.da6ffbc13bb1f9af56729fa38cc3f9f8.jpg" /></p>

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

<h2>
	الصياغة
</h2>

<p>
	إليك صياغة إنشاء الدالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3877_7" style="">
<span class="pln">let func </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Function</span><span class="pln"> </span><span class="pun">([</span><span class="pln">arg1</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">argN</span><span class="pun">],</span><span class="pln"> functionBody</span><span class="pun">);</span></pre>

<p>
	نصنع الدالة بالوُسطاء <code>‎arg1...argN‎</code> ونمرّر متنها <code>‎functionBody‎</code>.
</p>

<p>
	«هات الشيفرة وقلّل ثرثرتك»… صحيح، هذا أسهل. إليك الدالة وفيها وسيطين اثنين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3877_9" style="">
<span class="pln">let sum </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Function</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"> </span><span class="str">'return a + b'</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="pun">);</span><span class="pln"> </span><span class="com">// 3</span></pre>

<p>
	وهنا دالة بلا وُسطاء فيها متنها فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3877_11" style="">
<span class="pln">let sayHi </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Function</span><span class="pun">(</span><span class="str">'alert("Hello")'</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>
	الفرق الأساس بين هذه الطريقة والطرائق الأخرى هي أنّا نصنع الدالة هنا (كما لاحظت) من سلسلة نصية حرفيًا، ونمرّرها في وقت تشغيل الشيفرة.
</p>

<p>
	ألزمتنا التصريحات السابقة كلها - ألزمتنا نحن المطوّرين أن نكتب شيفرة الدالة في السكربت.
</p>

<p>
	ولكن صياغة <code>‎new Function‎</code> تسمح لنا بأن نحوّل أيّ سلسلة نصية لتصير دالة. فمثلًا يمكن أن نستلم دالة جديدة من أحد الخواديم وننفّذها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3877_13" style="">
<span class="pln">let 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="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 func </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Function</span><span class="pun">(</span><span class="pln">str</span><span class="pun">);</span><span class="pln">
func</span><span class="pun">();</span></pre>

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

<h2>
	المنغلقات
</h2>

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

<p>
	ولكن حين نصنع الدالة باستعمال <code>‎new Function‎</code> فتُضبط خاصية <code>‎[[Environment]]‎</code> على البيئة المُعجمية <em>العمومية</em> لا الحالية.
</p>

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

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

  let func </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Function</span><span class="pun">(</span><span class="str">'alert(value)'</span><span class="pun">);</span><span class="pln">

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

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

<p>
	وازن بين هذا والسلوك الطبيعي:
</p>

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

  let func </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">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"> func</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

getFunc</span><span class="pun">()();</span><span class="pln"> </span><span class="com">// ‫«test»، من بيئة getFunc المُعجمية</span></pre>

<p>
	صحيح أنّ الميزة الخاصة للصياغة <code>‎new Function‎</code> غريبة بعض الشيء، ولكنها عمليًا مفيدة جدًا.
</p>

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

<p>
	الآن، على دالتنا هذه التفاعل مع السكربت الرئيس.
</p>

<p>
	لكن ماذا لو أمكن لها أن ترى المتغيرات الخارجية؟
</p>

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

<p>
	فمثلًا لو كان في الدالة <code>‎let userName‎</code> فيستبدلها المُصغِّر إلى <code>‎let a‎</code> (أو أيّ حرف آخر لو هناك من أخذ الاسم)، وينفّذ هذا في كلّ مكان آخر. عادةً لا يضرّ ذلك إذ أنّ المتغير محلي ولا يمكن لما خارج الدالة رؤيته، بينما يستبدل المُصغِّر كلّ مرة يرد فيها المتغير داخل الدالة. هذه الأدوات ذكية فهي تحلّل بنية الشيفرة لألا تُعطبها، وليست كأدوات البحث والاستبدال الهمجية.
</p>

<p>
	لذا لو أرادت <code>‎new Function‎</code> أن تستعمل المتغيرات الخارجية فلن تعرف بوجود <code>‎userName‎</code> الذي تغيّر اسمه.
</p>

<p>
	<strong>لو أمكن للدوال <code>‎new Function‎</code> أن ترى المتغيرات الخارجية لكانت ستواجه مشاكل جمّة مع المُصغِّرات.</strong>
</p>

<p>
	كما وأنّ الشيفرات من هذا النوع ستكون سيّئة من حيث البنية وعُرضة للأخطاء والمشاكل.
</p>

<p>
	لو أردت تمرير شيء للدالة <code>‎new Function‎</code> فعليك استعمال مُعاملاتها.
</p>

<h2>
	ملخص
</h2>

<p>
	الصياغة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3877_19" style="">
<span class="pln">let func </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Function</span><span class="pln"> </span><span class="pun">([</span><span class="pln">arg1</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">argN</span><span class="pun">],</span><span class="pln"> functionBody</span><span class="pun">);</span></pre>

<p>
	ويمكن تمرير المُعاملات (لأسباب تاريخية أيضًا) في قائمة مفصولة بفواصل.
</p>

<p>
	هذه التصريحات الثلاث لا تفرق عن بعضها البعض:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3877_21" style="">
<span class="kwd">new</span><span class="pln"> </span><span class="typ">Function</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"> </span><span class="str">'return a + b'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// الصياغة الأساس</span><span class="pln">
</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Function</span><span class="pun">(</span><span class="str">'a,b'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'return a + b'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// مفصولة بفواصل</span><span class="pln">
</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Function</span><span class="pun">(</span><span class="str">'a , b'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'return a + b'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// مفصولة بفواصل ومسافات</span></pre>

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

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/new-function" rel="external nofollow">The "new Function" syntax</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">876</guid><pubDate>Thu, 16 Apr 2020 13:05:20 +0000</pubDate></item><item><title>&#x643;&#x627;&#x626;&#x646;&#x627;&#x62A; &#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; Function object &#x648;&#x62A;&#x639;&#x627;&#x628;&#x64A;&#x631; &#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; &#x627;&#x644;&#x645;&#x633;&#x645;&#x627;&#x629; NFE &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-function-object-%D9%88%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D9%85%D8%A7%D8%A9-nfe-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r875/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_04/49.jpg.768ef3d8f3c595f19886c81164ed4a77.jpg" /></p>

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

<p>
	ولكلّ قيمة في هذه اللغة نوع. ولكن ما نوع الدالة نفسها؟
</p>

<p>
	تُعدّ الدوال كائنات في جافاسكربت.
</p>

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

<h2>
	خاصية الاسم name
</h2>

<p>
	تحتوي كائنات الدوال على خاصيات يمكننا استعمالها.
</p>

<p>
	فمثلًا يمكن أن نعرف اسم الدالة من خاصية الاسم <code>‎name‎</code>:
</p>

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

alert</span><span class="pun">(</span><span class="pln">sayHi</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// sayHi</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_9" style="">
<span class="pln">let 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"</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">sayHi</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫sayHi (للدالة اسم!)</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_11" style="">
<span class="kwd">function</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="kwd">function</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">sayHi</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫sayHi (تعمل أيضًا!)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

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

<p>
	تُدعى هذه الميزة في توصيف اللغة «بالاسم السياقي». فلو لم تقدّم الدالة اسمًا لها فيحاول المحرّك معرفته من السياق مع أوّل عملية إسناد.
</p>

<p>
	كما ولتوابِع الكائنات أسماء أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_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">// ...</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  sayBye</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">}</span><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">sayHi</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// sayHi</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">sayBye</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// sayBye</span></pre>

<p>
	ولكن ليس للسحر مكان هنا، فهناك حالات يستحيل على المحرّك معرفة الاسم الصحيح منها، بهذا تكون خاصية الاسم فارغة، كما في هذه الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_15" 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="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"> 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">// &lt;سلسلة نصية فارغة&gt;</span><span class="pln">
</span><span class="com">// ما من طريقة يعرف بها المحرّك الاسم الصحيح، فباختصار، ليس هناك اسم!</span></pre>

<p>
	ولكن عمليًا، لكل الدوال أسماء أغلب الوقت.
</p>

<h2>
	خاصية الطول length
</h2>

<p>
	توجد خاصية أخرى مضمّنة في اللغة باسم <code>‎length‎</code> وهي تُعيد عدد مُعاملات الدالة. مثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_17" style="">
<span class="kwd">function</span><span class="pln"> f1</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">function</span><span class="pln"> f2</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">function</span><span class="pln"> many</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">more</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">f1</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">f2</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">many</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>
	نرى هنا بأن المُعاملات البقية لم تُحسب.
</p>

<p>
	يستعمل المطوّرون خاصية <code>‎length‎</code> أحيانًا <a href="https://en.wikipedia.org/wiki/Type_introspection" rel="external nofollow">لإجراء التحقّق الداخلي</a> داخل الدوال التي تعتمد في تشغيلها على التحكّم بدوال أخرى.
</p>

<p>
	في الشيفرة أسفله، تقبل دالة <code>‎ask‎</code> سؤالًا <code>‎question‎</code> تطرحه وعددًا غير محدّد من دوال المعالجة <code>‎handler‎</code> لتستدعيها دالة السؤال.
</p>

<p>
	فما إن ينزل الوحي على المستخدم ويُعطينا إجابة تستدعي الدالة المُعالجات. يمكننا تمرير نوعين اثنين من المُعالجات هذه:
</p>

<ul>
<li>
		دالة ليس لها وُسطاء لا تُنشأ إلا عندما يُعطيها المستخدم إجابة بالإيجاب.
	</li>
	<li>
		دالة لها وُسطاء تُستدعى في بقية الحالات وتُعيد إجابة المستخدم.
	</li>
</ul>
<p>
	علينا فحص خاصية <code>‎handler.length‎</code> لنستدعي <code>‎handler‎</code> بالطريقة السليمة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_19" style="">
<span class="kwd">function</span><span class="pln"> ask</span><span class="pun">(</span><span class="pln">question</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">handlers</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let isYes </span><span class="pun">=</span><span class="pln"> confirm</span><span class="pun">(</span><span class="pln">question</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let handler of handlers</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">handler</span><span class="pun">.</span><span class="pln">length </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isYes</span><span class="pun">)</span><span class="pln"> handler</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      handler</span><span class="pun">(</span><span class="pln">isYes</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

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

</span><span class="com">// يُعاد كِلا المُعالجان لو كانت الإجابة بالإيجاب</span><span class="pln">
</span><span class="com">// ولو كانت بالسلب، فالثاني فقط</span><span class="pln">
ask</span><span class="pun">(</span><span class="str">"Question?"</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="str">'You said yes'</span><span class="pun">),</span><span class="pln"> result </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln">result</span><span class="pun">));</span></pre>

<p>
	هذه حالة من حالات <a href="https://ar.wikipedia.org/wiki/%D8%AA%D8%B9%D8%AF%D8%AF_%D8%A7%D9%84%D8%A3%D8%B4%D9%83%D8%A7%D9%84_(%D8%B9%D9%84%D9%85_%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8)" rel="external nofollow">التعدّدية الشكلية</a>، أي حين يتغيّر تعاملنا مع الوُسطاء حسب أنواعها… في حالتنا فهي حسب أطوالها <code>‎length‎</code>. لهذه الفكرة استعمال فعليّ في مكتبات جافاسكربت.
</p>

<h2>
	خاصيات مخصصة
</h2>

<p>
	يمكننا أيضًا إضافة ما نريد من خاصيات.
</p>

<p>
	فهنا نُضيف خاصية العدّاد <code>‎counter‎</code> ليسجّل إجمالي عدد الاستدعاءات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_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="str">"Hi"</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">counter</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">counter </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">

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

alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`‎</span><span class="typ">Called</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">sayHi</span><span class="pun">.</span><span class="pln">counter</span><span class="pun">}</span><span class="pln"> times</span><span class="pun">‎`</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Called 2 times</span></pre>

<p>
	<strong>الخاصيات ليست متغيرات</strong> <em>لا تعرّف</em> الخاصية المُسندة إلى الدوال مثل <code>‎sayHi.counter = 0‎</code> متغيرًا محليًا فيها (<code>‎counter‎</code> في حالتنا). أي أنّ لا علاقة تربط الخاصية <code>‎counter‎</code> بالمتغير <code>‎let counter‎</code> البتة.
</p>

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

<p>
	يمكننا أحيانًا استعمال خاصيات الدوال بدل المُنغلِقات. فمثلًا يمكن إعادة كتابة تمرين دالة العدّ في فصل «المُنغلِقات» فنستعمل خاصية دالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_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">
  </span><span class="com">// بدل:</span><span class="pln">
  </span><span class="com">// let count = 0</span><span class="pln">

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

  counter</span><span class="pun">.</span><span class="pln">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"> counter</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></pre>

<p>
	هكذا خزّنا الخاصية <code>‎count‎</code> في الدالة مباشرةً وليس في بيئتها المُعجمية الخارجية.
</p>

<p>
	أهذه أفضل أم <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D9%86%D8%BA%D9%84%D9%82%D8%A7%D8%AA-closure-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r872/" rel="">المنغلقات</a> أفضل؟
</p>

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

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

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

  counter</span><span class="pun">.</span><span class="pln">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"> counter</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">

</span><span class="com">// هذا</span><span class="pln">
counter</span><span class="pun">.</span><span class="pln">count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</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">// 10</span></pre>

<p>
	إذًا فالخيار يعود لنا: ماذا نريد وما الغاية.
</p>

<h2>
	تعابير الدوال المسماة
</h2>

<p>
	كما اسمها، فتعابير الدوال المسمّاة (<strong>N</strong>amed <strong>F</strong>unction <strong>E</strong>xpression) هي تعابير الدوال التي لها اسم… بسيطة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_27" style="">
<span class="pln">let sayHi </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`‎</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">who</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_219_29" style="">
<span class="pln">let sayHi </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`‎</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">who</span><span class="pun">}‎`);</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	هل حللنا أزمة عالمية هنا؟ ما الداعي من هذا الاسم <code>‎"func"‎</code>؟
</p>

<p>
	أولًا، ما زال أمامنا تعبير دالة، فإضافة الاسم <code>‎"func"‎</code> بعد <code>‎function‎</code> لم يجعل الجملة تصريحًا عن دالة إذ ما زلنا نصنع الدالة داخل جزء من تعبير إسناد.
</p>

<p>
	كما وإضافة الاسم لم يُعطب الدالة بأي شكل. يمكن أن ندخل الدالة هكذا <code>‎sayHi()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_31" style="">
<span class="pln">let sayHi </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`‎</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">who</span><span class="pun">}‎`);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

sayHi</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>
	ثمّة أمرين مميزين بهذا الاسم <code>‎func‎</code> وهما السبب وراء كل هذا:
</p>

<ol>
<li>
		يتيح الاسم بأن تُشير الدالة إلى نفسها داخليًا.
	</li>
	<li>
		ولا يظهر الاسم لما خارج الدالة.
	</li>
</ol>
<p>
	فمثلًا تستدعي الدالة <code>‎sayHi‎</code> أسفله نفسها ثانيةً بالوسيط <code>‎"Guest"‎</code> لو لم نمرّر لها <code>‎who‎</code> من البداية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_33" style="">
<span class="pln">let sayHi </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">who</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">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(`‎</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">who</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">
    func</span><span class="pun">(</span><span class="str">"Guest"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫نستعمل func لنستدعي نفسنا ثانيةً</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><span class="pln"> </span><span class="com">// Hello, Guest</span><span class="pln">

</span><span class="com">// ولكن هذا لن يعمل:</span><span class="pln">
func</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ‫ويعطينا خطأً بأنّ func غير معرّفة (فالدالة لا تظهر لما خارجها)</span></pre>

<p>
	ولكن لمَ نستعمل <code>‎func‎</code> أصلًا؟ ألا يمكن أن نستعمل <code>‎sayHi‎</code> لذلك الاستدعاء المتداخل؟
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_35" style="">
<span class="pln">let sayHi </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">who</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">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(`‎</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">who</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">
    sayHi</span><span class="pun">(</span><span class="str">"Guest"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	مشكلة تلك الشيفرة هي احتمالية تغيّر <code>‎sayHi‎</code> في الشيفرة الخارجية. فلو أُسندت الدالة إلى متغير آخر بدل ذاك فستبدأ الأخطاء تظهر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_37" style="">
<span class="pln">let sayHi </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">who</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">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(`‎</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">who</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">
    sayHi</span><span class="pun">(</span><span class="str">"Guest"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫خطأ: sayHi ليست بدالة</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let welcome </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"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

welcome</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ‫خطأ: لم يعد الاستدعاء المتداخل sayHi يعمل بعد الآن!</span></pre>

<p>
	سبب ذلك هو أنّ الدالة تأخذ <code>‎sayHi‎</code> من بيئتها المُعجمية الخارجية إذ لا تجد <code>‎sayHi‎</code> محليًا فيها فتستعمل المتغير الخارجي. وفي لحظة الاستدعاء تلك يكون <code>‎sayHi‎</code> الخارجي قد صار <code>‎null‎</code>.
</p>

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

<p>
	هيًا نُصلح شيفرتنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_39" style="">
<span class="pln">let sayHi </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">who</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">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(`‎</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">who</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">
    func</span><span class="pun">(</span><span class="str">"Guest"</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 welcome </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"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

welcome</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ‫Hello, Guest (الاستدعاءات المتداخلة تعمل)</span></pre>

<p>
	الآن صارت تعمل إذ الاسم <code>‎"func"‎</code> محليّ للدالة فقط ولا تأخذها من الخارج (ولا تظهر للخارج أيضًا). تضمن لنا مواصفات اللغة بأنّها ستُشير دومًا وأبدًا إلى الدالة الحالية.
</p>

<p>
	مع ذلك فما زالت الشيفرة الخارجية تملك المتغيرين <code>‎sayHi‎</code> و<code>‎welcome‎</code>، بينما <code>‎func‎</code> هو «اسم الدالة داخليًا» أي كيف تستدعي الدالة نفسها من داخلها.
</p>

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

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

<h2>
	ملخص
</h2>

<p>
	تُعدّ الدوال كائنات. شرحنا في الفصل خصائصها:
</p>

<ul>
<li>
		اسمها <code>‎name‎</code> -- غالبًا ما يأتي من تعريف الدالة. لكن لو لم يكن هناك واحد فيحاول المحرّك تخمينه من السياق (مثلًا من عبارة الإسناد).
	</li>
	<li>
		عدد مُعاملتها في تعريف الدالة <code>‎length‎</code> -- لا تُحسب المُعاملات البقية.
	</li>
</ul>
<p>
	لو عرّفنا الدالة باستعمال تعبير عن دالة (وليس في الشيفرة الأساس)، وكان لهذه الدالة اسم فنُسمّيها بتعبير الدالة المسمّى.
</p>

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

<p>
	إذ تُنشئ دالة «رئيسة» بعدها تُرفق دوال أخرى «مُساعِدة» إليها. فمثلًا تُنشئ مكتبة <a href="https://jquery.com" rel="external nofollow">jQuery</a> الدالة بالاسم <code>‎$‎</code>، وتُنشئ مكتبة <a href="https://lodash.com" rel="external nofollow">lodash</a> الدالة بالسم <code>‎_‎</code> ثمّ تُضيف خاصياتها <code>‎_.clone‎</code> و <code>‎_.keyBy‎</code> وغيرها (طالع <a href="https://lodash.com/docs" rel="external nofollow">docs</a> متى أردت معرفتها أكثر). ما تفعله هذه الدوال يعود إلى أنّها (في الواقع) تحاول حدّ «التلوّث» في المجال العمومي فلا تستعمل المكتبة إلّا متغيرًا عموميًا واحدًا. وهذا يُقلّل من أدنى إمكانية لتضارب الأسماء.
</p>

<p>
	إذًا، فالدالة تؤدي عملًا رائعًا كما هي، وأيضًا تحوي على وظائف أخرى خاصيات لها.
</p>

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

<h3>
	ضبط قيمة العداد وإنقاصها
</h3>

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

<p>
	عدّل شيفرة الدالة <code>‎makeCounter()‎</code> بحيث يُنقص العدّاد قيمتها إضافةً إلى ضبطها:
</p>

<ul>
<li>
		على <code>‎counter()‎</code> إعادة العدد التالي (كما في الأمثلة السابقة).
	</li>
	<li>
		على <code>‎counter.set(value)‎</code> ضبط قيمة العدّاد لتكون <code>‎value‎</code>.
	</li>
	<li>
		على <code>‎counter.decrease()‎</code> إنقاص قيمة العدّاد واحدًا (1).
	</li>
</ul>
<p>
	طالِع الشيفرة أدناه كي تعرف طريقة استعمال الدالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_41" 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="com">// ... شيفرتك هنا ...</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">

counter</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="lit">10</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"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 10</span><span class="pln">

counter</span><span class="pun">.</span><span class="pln">decrease</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">// ‫10 (بدل 11)</span></pre>

<p>
	ملاحظة: يمكنك استعمال مُنغلِق أو خاصية دالة لحفظ العدد الحالي، أو لو أردت فاكتب الحل بالطريقتين.
</p>

<h4>
	الحل
</h4>

<p>
	يستعمل الحل المتغير <code>‎count‎</code> محليًا، كما وتوابِع أخرى نكتبها داخل الدالة <code>‎counter‎</code>. تتشارك هذه التوابِع ذات البيئة المُعجمية الخارجية كما وترى أيضًا قيمة <code>‎count‎</code> الحالية. 
</p>

<h3>
	مجموع ما في الأقواس أيًا كان عدد الأقواس
</h3>

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

<p>
	اكتب الدالة <code>‎sum‎</code> لتعمل كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_43" 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="pun">;</span><span class="pln"> </span><span class="com">// 1 + 2</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="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">6</span><span class="pun">;</span><span class="pln"> </span><span class="com">// 1 + 2 + 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="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
sum</span><span class="pun">(</span><span class="lit">6</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="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
sum</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="lit">4</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="lit">15</span></pre>

<p>
	تريد تلميحًا؟ ربما تكتب كائنًا مخصّصًا يُحوّل الأنواع الأولية لتُناسب الدالة.
</p>

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

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

  let currentSum </span><span class="pun">=</span><span class="pln"> a</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">b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    currentSum </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"> f</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">toString </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"> currentSum</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"> f</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="lit">2</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"> sum</span><span class="pun">(</span><span class="lit">6</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="pun">);</span><span class="pln"> </span><span class="com">// 0</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> sum</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="lit">4</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">// 15</span></pre>

<p>
	لاحظ بأنّ دالة <code>‎sum‎</code> تعمل مرّة واحدة فقط لا غير، وتُعيد الدالة <code>‎f‎</code>.
</p>

<p>
	وبعدها في كلّ استدعاء يليها، تُضيف <code>‎f‎</code> المُعامل إلى المجموع <code>‎currentSum‎</code> وتُعيد نفسها.
</p>

<p>
	<strong>لا نستعمل التعاود في آخر سطر من <code>‎f‎</code>.</strong>
</p>

<p>
	هذا شكل التعاود:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_47" style="">
<span class="kwd">function</span><span class="pln"> f</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">
  currentSum </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"> f</span><span class="pun">();</span><span class="pln"> </span><span class="com">// &lt;-- استدعاء تعاودي</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بينما في حالتنا نُعيد الدالة دون استدعائها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_219_49" style="">
<span class="kwd">function</span><span class="pln"> f</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">
  currentSum </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"> f</span><span class="pun">;</span><span class="pln"> </span><span class="com">// &lt;-- لا تستدعي نفسها، بل تُعيد نفسها</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وستُستعمل <code>‎f‎</code> هذه في الاستدعاء التالي، وتُعيد نفسها ثانيةً مهما لزم. وبعدها حين نستعمل العدد أو السلسلة النصية، يُعيد التابِع <code>‎toString‎</code> المجموع <code>‎currentSum‎</code>. يمكن أيضًا أن نستعمل <code>‎Symbol.toPrimitive‎</code> أو <code>‎valueOf‎</code> لإجراء عملية التحويل.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/function-object" rel="external nofollow">Function object, NFE</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">875</guid><pubDate>Fri, 17 Apr 2020 05:23:39 +0000</pubDate></item></channel></rss>
