الأحداث
بجانب باب الشقة جرس واحد. الزر هو #bell ومكتوب عليه press. تحته الفقرة #chime ما زالت تقول silent. لا توجد سمة onclick في HTML، لذلك bell.onclick يبدأ بـ null.
فخ قديم: typeof null في JavaScript يساوي "object". إذن typeof bell.onclick هو "object" أيضًا، لا "null" ولا "undefined". المقارنة bell.onclick === null صحيحة.
وضع دالة في onclick لا يقرع الجرس. يبقى النص silent إلى أن ينفّذ bell.click() الدالة الموجودة في الخانة. الخانة تتسع لدالة واحدة. إذا عيّنت دالة ثانية، تذهب الأولى. نقرة واحدة لا تشغّل الاثنتين. addEventListener للصفحة التالية؛ هناك تتراكم المستمعات. هذه الصفحة لا تستدعيه.
bell.onclick = null يفرّغ الخانة. النقرة بعد ذلك لا تغيّر النص. داخل الدالة، this هو الزر نفسه وthis.id يساوي bell. كلمة الزر تبقى press. سكربت الصفحة ينقر مرة واحدة. السطر تحت الجرس: dong / 1 / bell. لا ننشئ عنصرًا هنا ولا نضبط نمطًا.
خانة واحدة على الزر
الصفحة السابقة بنت عناصر li بـ createElement ثم وضعتها بـ append وprepend وinsertBefore. هنا لا نبني عقدة ولا نقرأ children. الصفحة التي قبلها كتبت style وclassList على شريحة لون. هنا لا نعيّن style. getElementById يعطيك الزر والفقرة فقط. الفكرة الجديدة هي خاصية onclick: دالة واحدة، أو null.
ماذا في الخانة
الزر يبدأ بـ press وتحته silent. اقرأ الصفوف بالترتيب. كل مقتطف يبدأ من الزر الجديد، ما عدا صف الصفحة وهو عرض الأسفل. ذلك العرض لا يعيّن null.
📊 ماذا في الخانة
| اللحظة | ما يحمله onclick |
نص الجرس | الخلط الشائع |
|---|---|---|---|
| قبل أي تعيين | null؛ وtypeof هو "object" |
silent | قراءة typeof كأنها "null" |
بعد دالة ding وقبل click |
دالة | silent | ظن أن التعيين نفسه يقرع الجرس |
بعد click مع ding |
تلك الدالة | ding | تحوّل نص الزر إلى ding |
dong تحل محل ding ثم click واحد |
دالة dong لا ding | dong | تشغيل الدالتين معًا |
onclick = null ثم click على زر جديد |
null؛ وtypeof هو "object" |
silent | خانة فارغة ما زالت تقرع |
سكربت الصفحة، click واحد |
دالة؛ وthis.id هو bell |
dong | انتهاء السطر بـ silent |
onclick خاصية على العنصر. بلا معالج تكون القيمة null، وtypeof null يبقى "object". استعمل === null إذا أردت أن تعرف أن الخانة فارغة. التعيين يخزّن الدالة ولا يستدعيها. bell.click() يطلق نقرة ويشغّل الدالة الموجودة في الخانة تلك اللحظة. نص الزر نفسه لا يتغير. التعيين الثاني يكتب فوق الخاصية. إذا أبقيت اسمًا للدالة الأولى، الكائن ما زال في الذاكرة، لكن الخاصية لم تعد تشير إليه. onclick = null يزيل المعالج. سمة onclick في HTML تملأ الخانة نفسها؛ هذا الزر بلا سمة. دالة سهمية في هذه الخانة لا تجعل this هو الزر. هذه الصفحة تستعمل function عادية.
الخانة فارغة من البداية
الملف يفتح بالزر والفقرة. لم يُعيَّن شيء بعد. هذه السجلات الأربعة تسأل الخاصية وtypeof ونص الجرس وكلمة الزر.
let bell = document.getElementById("bell");
let chime = document.getElementById("chime");
console.log(bell.onclick);
console.log(typeof bell.onclick);
console.log(chime.textContent);
console.log(bell.textContent);
النواتج: null وobject وsilent وpress. الخانة فارغة. typeof لا يطبع كلمة null. الزر والفقرة ما زالا يعرضان كلمتَي الترميز.
الدالة تنتظر
onclick = function ... يخزّن الدالة. الجسم لا يعمل في ذلك السطر. الجرس ما زال silent والخانة لم تعد null.
let bell = document.getElementById("bell");
let chime = document.getElementById("chime");
bell.onclick = function () {
chime.textContent = "ding";
};
console.log(typeof bell.onclick);
console.log(chime.textContent);
console.log(bell.onclick === null);
النواتج: function وsilent وfalse. ترى دالة في الخانة. الفقرة لم تتغير لأن أحدًا لم يستدعِ الدالة.
click يشغّل ما في الخانة
bell.click() يشغّل المعالج الحالي. يصير الجرس ding. نص الزر يبقى press. بعد النقرة ما زالت الخانة تحمل دالة.
let bell = document.getElementById("bell");
let chime = document.getElementById("chime");
bell.onclick = function () {
chime.textContent = "ding";
};
bell.click();
console.log(chime.textContent);
console.log(bell.textContent);
console.log(typeof bell.onclick);
النواتج: ding وpress وfunction. نقرة واحدة وتغيير واحد، والتغيير في الفقرة. كلمة press ما زالت على الزر.
الدالة الثانية تحل محل الأولى
هذا المقتطف يبدأ من الزر الجديد. تُخزَّن ding ثم تُكتب dong فوقها، وبعد ذلك تأتي نقرة واحدة. لا نقرة بين التعيينين، لذلك لا يصير الجرس ding في هذا التشغيل. بعد النقرة يصير dong. bell.onclick === ding يساوي false. bell.onclick === dong يساوي true.
let bell = document.getElementById("bell");
let chime = document.getElementById("chime");
function ding() {
chime.textContent = "ding";
}
function dong() {
chime.textContent = "dong";
}
bell.onclick = ding;
bell.onclick = dong;
bell.click();
console.log(bell.onclick === ding);
console.log(bell.onclick === dong);
console.log(chime.textContent);
النواتج: false وtrue وdong. الاسم ding ما زال يشير إلى دالة. الخاصية لا تشير إليها. النقرة الواحدة شغّلت dong فقط.
null يفرّغ الخانة
شغّل هذا على الزر الجديد. تُعيَّن دالة ثم تُمسح قبل أي نقرة. bell.click() بعد null لا يكتب dong. يبقى الجرس silent. typeof يعود object لأن القيمة null.
let bell = document.getElementById("bell");
let chime = document.getElementById("chime");
bell.onclick = function () {
chime.textContent = "dong";
};
bell.onclick = null;
bell.click();
console.log(bell.onclick);
console.log(typeof bell.onclick);
console.log(chime.textContent);
النواتج: null وobject وsilent. الدالة التي كانت ستكتب dong ليست في الخانة وقت النقرة. عرض الصفحة في الأسفل لا يفرّغ الخانة.
سطر تحت الجرس
السكربت في آخر body، بعد الزر والفقرة. يخزّن دالة واحدة ثم يستدعي click مرة. داخل الدالة يرتفع taps من 0 إلى 1، ويصير الجرس dong، ويُكتب this.id في bell.dataset.who. السطر يجمع نص الجرس والعدد وذلك المعرّف. لا يكتب نص الزر.
<!DOCTYPE html>
<html>
<head>
<title>events — page</title>
</head>
<body>
<button id="bell" type="button">press</button>
<p id="chime">silent</p>
<p id="line">…</p>
<script>
let bell = document.getElementById("bell");
let chime = document.getElementById("chime");
let taps = 0;
bell.onclick = function () {
taps = taps + 1;
chime.textContent = "dong";
bell.dataset.who = this.id;
};
bell.click();
document.getElementById("line").textContent =
chime.textContent + " / " + taps + " / " + bell.dataset.who;
</script>
</body>
</html>
السطر يصير dong / 1 / bell. الجرس dong لا silent. العدد 1 لأن السكربت ينقر مرة. الرمز الأخير هو معرّف الزر من this داخل المعالج، لا كلمة press. الزر ما زال يقول press. الصفحة التالية عن مستمعي الأحداث، وأداتها الرئيسة ليست خانة onclick الواحدة هذه.
خمس قرعات للتحقق
- اقرأ
onclickوtypeof bell.onclickونص الجرس ونص الزر. القيم: null وobject وsilent وpress. - عيّن دالة ding ولا تنقر.
typeofيصير function، والجرس silent، وonclick === nullيساوي false. - استدعِ
bell.click()مع دالة ding. الجرس ding، والزر press، وtypeofهو function. - عيّن ding ثم dong ثم انقر مرة.
onclick === dingيساوي false، وonclick === dongيساوي true، والجرس dong. - على زر جديد عيّن دالة ثم اجعل
onclickمساويًا null ثم انقر. القيم: null وobject وsilent. سطر الصفحة: dong / 1 / bell.
أين يخدعك هذا الجرس
الزر ما زال يقول press. إما أن الخانة حملت الدالة الخطأ، أو أنها كانت فارغة.
- قراءة
typeof bell.onclickكأنها"null"والقيمةnull - توقع أن التعيين نفسه يغيّر الجرس إلى ding
- توقع أن
dingوdongتعملان معًا بنقرة واحدة بعد التعيين الثاني - توقع أن نص الزر يصير ding
- توقع أن
clickيغيّر الجرس بعدonclick = null - استعمال دالة سهمية وتوقع أن
this.idيساوي bell - قراءة
event.targetهنا؛ هذه الدوال بلا وسيط، وكائن الحدث لصفحة لاحقة - استدعاء
addEventListenerهنا؛ الصفحة التالية تكدّس المستمعات - بناء الزر بـ
createElement؛ ذلك كان عمل الصفحة السابقة - قراءة السطر كأنه silent / 0 / press
ما يبقى معك
- بلا معالج،
bell.onclickيساوي null وtypeof bell.onclickيساوي object - تعيين الدالة يُبقي الجرس silent إلى حين
click bell.click()مع دالة ding يجعل الجرس ding ويبقي الزر press- التعيين الثاني يحل محل الأول، فنقرة واحدة تشغّل dong فقط
onclick = nullثمclickعلى زر جديد يُبقي الجرس silent- سطر الصفحة يصير dong / 1 / bell و
this.idداخل المعالج هو bell
🧠 اختبر معرفتك
اختبر معرفتك
تحدى نفسك مع هذا الاختبار التفاعلي واكتشف مدى فهمك للموضوع
📝 التعليمات
- اقرأ كل سؤال بعناية
- اختر أفضل إجابة لكل سؤال
- يمكنك إعادة الاختبار عدة مرات كما تريد
- سيتم عرض تقدمك في الأعلى