JS

الجزء الحادي عشر – Events & Event Listeners في JavaScript – سلسلة FSWD – JS

🟡 أولًا: أنواع الأحداث

الأحداث في JavaScript هي التفاعلات أو التغييرات اللي بتحصل على الصفحة. JavaScript بتتيح لك التفاعل مع مجموعة من الأحداث المتنوعة زي:

  • click: عند الضغط على عنصر.

  • mouseover: عندما يتحرك المؤشر فوق عنصر.

  • mouseout: عندما يخرج المؤشر من عنصر.

  • keydown و keyup: عند الضغط أو رفع اليد عن مفتاح من لوحة المفاتيح.

  • input: عند تغيير قيمة حقل إدخال.

  • submit: عند إرسال نموذج.

  • resize: عندما يتم تغيير حجم نافذة المتصفح.

  • focus و blur: عند ترك أو إدخال عنصر مُركّز.

✅ مثال

<button id="clickBtn">اضغط هنا</button>
<input type="text" id="nameInput" placeholder="أدخل اسمك">

<script>
  // حدث click
  let btn = document.getElementById("clickBtn");
  btn.addEventListener("click", function() {
    alert("تم الضغط على الزر!");
  });

  // حدث input
  let inputField = document.getElementById("nameInput");
  inputField.addEventListener("input", function() {
    console.log("قيمة الحقل:", inputField.value);
  });
</script>

🟡 ثانيًا: this keyword في الأحداث

الـ this في JavaScript بتستخدم للإشارة إلى العنصر الذي تم عليه الحدث.

✅ مثال 1: في الدوال العادية

<button id="clickBtn">اضغط هنا</button>

<script>
  let btn = document.getElementById("clickBtn");
  btn.addEventListener("click", function() {
    console.log(this);  // هذا سيشير إلى الزر الذي تم عليه الضغط
  });
</script>

الـ this في المثال ده بتشير للزر الذي تم الضغط عليه.


✅ مثال 2: باستخدام Arrow Functions

في الدوال السهمية (Arrow Functions)، الـ this لا يشير إلى العنصر الذي حدث عليه الحدث، بل يشير إلى الـ محیط التنفيذ (Execution Context) اللي تم فيه تعريف الـ Arrow Function

<button id="clickBtn">اضغط هنا</button>

<script>
  let btn = document.getElementById("clickBtn");
  btn.addEventListener("click", () => {
    console.log(this);  // في Arrow Function, this لا يشير إلى الزر
  });
</script>

في الحالة دي، الـ this مش هيشير للزر لأن الـ Arrow Function بتحتفظ بـ this من السياق الخارجي لها.


🟡 ثالثًا: Event Bubbling و Event Delegation

Event Bubbling

Event Bubbling هو مفهوم يعني أن الحدث الذي يحدث على عنصر معين يمر عبر جميع العناصر الأب له في DOM.

مثلاً، لو كان عندك حدث click على عنصر داخل آخر، فإن الحدث سيصل أولاً للعنصر الذي حدث عليه، ثم ينتقل للأب الأعلى وهكذا حتى يصل إلى الـ document في النهاية.

✅ مثال على Event Bubbling

<div id="outerDiv" style="width: 300px; height: 300px; background-color: lightblue;">
  <button id="innerButton">اضغط هنا</button>
</div>

<script>
  let outerDiv = document.getElementById("outerDiv");
  let innerButton = document.getElementById("innerButton");

  // حدث على الزر
  innerButton.addEventListener("click", function() {
    alert("تم الضغط على الزر!");
  });

  // حدث على العنصر الأب
  outerDiv.addEventListener("click", function() {
    alert("تم الضغط داخل div!");
  });
</script>

في المثال ده، لما تضغط على الزر، الحدث سيصل أولاً للزر، ثم ينتقل للأب outerDiv. مفهوم bubbling يعني أن الحدث “يتصاعد” من العنصر الداخلي إلى الأعلى.

Event Delegation

Event Delegation هو أسلوب لتقليل التكرار في الكود باستخدام الـ Event Bubbling. بدل ما تضيف مستمع حدث (event listener) على كل عنصر فرعي، ممكن تضيفه على العنصر الأب وتستفيد من Bubbling.

✅ مثال على Event Delegation:

<div id="parentDiv">
  <button class="childBtn">زر 1</button>
  <button class="childBtn">زر 2</button>
  <button class="childBtn">زر 3</button>
</div>

<script>
  let parentDiv = document.getElementById("parentDiv");

  // إضافة حدث على العنصر الأب
  parentDiv.addEventListener("click", function(e) {
    // إذا تم الضغط على زر من الأزرار الفرعية
    if (e.target && e.target.classList.contains("childBtn")) {
      alert("تم الضغط على الزر: " + e.target.textContent);
    }
  });
</script>

هنا، احنا ضفنا حدث الـ click على العنصر الأب parentDiv، وبعدها تحققنا إذا كان العنصر الذي تم الضغط عليه هو أحد الأزرار الفرعية عن طريق e.target. كده هنقدر نضيف حدث واحد لجميع الأزرار بدل ما نضيف event listener لكل زر على حدة.


✅ 💯 مثال كامل

<!DOCTYPE html>
<html lang="ar">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Events Example</title>
</head>
<body>
  <h1>تعامل مع الأحداث في JavaScript</h1>

  <!-- عناصر HTML -->
  <button id="clickBtn">اضغط هنا</button>
  <input type="text" id="nameInput" placeholder="أدخل اسمك">

  <!-- عناصر لـ Event Bubbling & Event Delegation -->
  <div id="parentDiv">
    <button class="childBtn">زر 1</button>
    <button class="childBtn">زر 2</button>
    <button class="childBtn">زر 3</button>
  </div>

  <!-- سكربت JavaScript -->
  <script>
    // 1. التعامل مع حدث click
    let btn = document.getElementById("clickBtn");
    btn.addEventListener("click", function() {
      alert("تم الضغط على الزر!");
    });

    // 2. التعامل مع حدث input
    let inputField = document.getElementById("nameInput");
    inputField.addEventListener("input", function() {
      console.log("قيمة الحقل:", inputField.value);
    });

    // 3. استخدام Event Bubbling
    let parentDiv = document.getElementById("parentDiv");
    parentDiv.addEventListener("click", function(e) {
      if (e.target && e.target.classList.contains("childBtn")) {
        alert("تم الضغط على الزر: " + e.target.textContent);
      }
    });
  </script>
</body>
</html>

ملخص النقاط:

  1. أنواع الأحداث:

    • click, mouseover, input, keydown وغيرها.

  2. this keyword:

    • يشير إلى العنصر الذي حدث عليه الحدث في الدوال التقليدية.

    • في الـ Arrow Functions، this يشير إلى السياق الخارجي.

  3. Event Bubbling:

    • الحدث يتصاعد من العنصر الذي حدث عليه إلى العناصر الأب.

  4. Event Delegation:

    • بدلاً من إضافة مستمع حدث لكل عنصر، يمكن إضافة مستمع حدث واحد على العنصر الأب.

نطاق المتغيرات (Scope) في JavaScript

نطاق المتغيرات هو المكان أو النطاق اللي بيتم فيه تعريف المتغيرات، وده بيحدد مكان الوصول أو التعديل عليها في الكود.


🟡 أولًا: Global Scope vs Local Scope

Global Scope (النطاق العالمي)

أي متغير يتم تعريفه خارج أي دالة أو كتلة تعليمات (block) بيكون في النطاق العالمي. المتغيرات في النطاق العالمي يمكن الوصول إليها من أي مكان في الكود.

Local Scope (النطاق المحلي)

أي متغير يتم تعريفه داخل دالة أو داخل كتلة (مثل if أو for) بيكون في النطاق المحلي، وبالتالي لا يمكن الوصول إليه إلا داخل هذه الدالة أو الكتلة.


✅ مثال على Global Scope و Local Scope:

// متغير في النطاق العالمي
let globalVar = "أنا في النطاق العالمي";

function testScope() {
  // متغير في النطاق المحلي
  let localVar = "أنا في النطاق المحلي";
  console.log(globalVar); // ممكن الوصول للمتغير العالمي
  console.log(localVar);  // ممكن الوصول للمتغير المحلي
}

testScope();

console.log(globalVar);  // ممكن الوصول للمتغير العالمي
console.log(localVar);   // هنا هتحصل على خطأ لأن localVar معرف فقط داخل الدالة

 

✅ النتيجة:

  • الكود هيطبع globalVar من داخل الدالة لأنها في النطاق العالمي.

  • لكن لما تحاول الوصول لـ localVar خارج الدالة، هتحصل على خطأ لأن المتغير ده موجود فقط داخل الدالة.


🟡 ثانيًا: Hoisting في JavaScript

Hoisting هو مفهوم بيحصل فيه “رفع” أو “تحريك” تعريف المتغيرات والدوال في JavaScript. يعني، الكود بيتنفذ بشكل صاعد، وبالتالي بيتم رفع المتغيرات والدوال قبل تنفيذ الكود.

كيف يعمل Hoisting؟

  • المتغيرات المعلنة باستخدام var يتم رفع تعريف المتغير فقط، مش القيمة.

  • الدوال يتم رفع التعريف والتنفيذ بالكامل.

✅ مثال 1: Hoisting مع var

console.log(myVar);  // undefined
var myVar = "Hello";

console.log(myVar);  // "Hello"

✅ شرح:

  • في السطر الأول، عندما حاولنا الوصول إلى myVar قبل أن يتم تعريفه، الطباعة كانت undefined لأنه تم رفع التعريف فقط بدون القيمة.

  • بعد التعريف، أصبح myVar يحتوي على "Hello".

✅ مثال 2: Hoisting مع الدوال (Function Hoisting)

greet();  // "Hello!"

function greet() {
  console.log("Hello!");
}

✅ شرح:

  • الدالة greet() تم رفعها بالكامل، وبالتالي يمكن استدعاء الدالة قبل تعريفها في الكود.


🟡 ثالثًا: Hoisting مع let و const

في حال استخدام let و const، عملية hoisting لا تعمل بنفس الطريقة كما في var. بالرغم من أن تعريف المتغيرات يتم رفعه، لكن القيمة لا تكون موجودة، وبالتالي إذا حاولت الوصول إليها قبل تعريفها، هتحصل على خطأ ReferenceError.

✅ مثال مع let و const:

console.log(myVar);  // ReferenceError: Cannot access 'myVar' before initialization
let myVar = "Hello";

 

✅ شرح:

  • هنا، يتم رفع myVar ولكن لا يمكن الوصول إليها قبل تعريفها، وبالتالي يحدث خطأ.


✅ 💯 مثال كامل على Scope و Hoisting:

<!DOCTYPE html>
<html lang="ar">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Scope and Hoisting Example</title>
</head>
<body>
  <script>
    // 1. Global Scope
    let globalVar = "أنا متغير في النطاق العالمي";

    function testScope() {
      // 2. Local Scope
      let localVar = "أنا متغير في النطاق المحلي";

      console.log(globalVar);  // الوصول للمتغير في النطاق العالمي
      console.log(localVar);   // الوصول للمتغير في النطاق المحلي
    }

    testScope();

    console.log(globalVar);  // ممكن الوصول للمتغير العالمي
    // console.log(localVar); // هتحصل على خطأ هنا لأن localVar معرف فقط داخل الدالة

    // 3. Hoisting Example with var
    console.log(myVar);  // undefined
    var myVar = "Hello from var";

    console.log(myVar);  // "Hello from var"

    // 4. Hoisting Example with function
    greet();  // "Hello, world!"
    function greet() {
      console.log("Hello, world!");
    }

    // 5. Hoisting Example with let
    // console.log(myLet);  // ReferenceError: Cannot access 'myLet' before initialization
    let myLet = "Hello from let";

    // 6. Hoisting Example with const
    // console.log(myConst);  // ReferenceError: Cannot access 'myConst' before initialization
    const myConst = "Hello from const";
  </script>
</body>
</html>

✅ شرح الكود:

  1. Global Scope: globalVar معرف في النطاق العالمي، وبالتالي يمكن الوصول إليه من أي مكان في الكود.

  2. Local Scope: localVar معرف داخل الدالة testScope()، وبالتالي لا يمكن الوصول إليه خارج الدالة.

  3. Hoisting مع var: عند الوصول إلى myVar قبل تعريفه، الطباعة كانت undefined لأن var بيتم رفع التعريف فقط.

  4. Hoisting مع دوال: الدالة greet() يتم رفعها بالكامل، وبالتالي يمكن استدعاء الدالة قبل تعريفها في الكود.

  5. Hoisting مع let و const: مع let و const، عند محاولة الوصول للمتغير قبل تعريفه يحدث خطأ ReferenceError.


ملخص النقاط:

  1. Global Scope:

    • المتغيرات المعرّفة في النطاق العالمي يمكن الوصول إليها من أي مكان في الكود.

  2. Local Scope:

    • المتغيرات المعرّفة داخل دالة أو كتلة لا يمكن الوصول إليها إلا داخل تلك الدالة أو الكتلة.

  3. Hoisting:

    • var يتم رفعه بشكل جزئي (التعريف فقط).

    • الدوال يتم رفعها بالكامل (التعريف والتنفيذ).

    • let و const يتم رفع تعريف المتغير فقط، ولكن لا يمكن الوصول إليه قبل تعريفه، مما يؤدي إلى ReferenceError.

فرص الربح من الإنترنت

💰 هل تبحث عن طريقة سهلة للربح من الإنترنت؟

ابدأ الآن واكسب أموالًا حقيقية من خلال خطوات بسيطة! 🌟

اضغط وابدأ الربح

📱 اربح من هاتفك فقط!

كل ما تحتاجه هو اتصال بالإنترنت وبعض الوقت ⏳

ابدأ الربح الآن

🚀 اربح المال وأنت في بيتك

الفرصة أمامك الآن وبخطوات سهلة ومضمونة!

من هنا تبدأ رحلتك

🔥 لا تحتاج إلى خبرة أو رأس مال!

اربح الآن من الإنترنت بأبسط الطرق

اضغط هنا للربح

💸 دخل إضافي بدون تعب؟

🤩 هذه فرصتك لتبدأ في الربح من الإنترنت!

سارع الآن

مقالات ذات صلة

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

زر الذهاب إلى الأعلى