١٥ ديسمبر ٢٠٢١

خصائص العقدة: النوع والعلامة والمحتويات

دعنا نلقي نظرة أكثر تعمقًا على عقد DOM.

في هذا الفصل ، سنرى المزيد عن ماهيتها ونتعلم خصائصها الأكثر استخدامًا.

فئات عقدة DOM

قد تحتوي عقد DOM المختلفة على خصائص مختلفة. على سبيل المثال ، عقدة عنصر مقابلة للعلامة <a> لها خصائص مرتبطة بالارتباط ، والعقدة المقابلة لـ <input> لها خصائص تتعلق بالإدخال وما إلى ذلك. العقد النصية ليست مثل عقد العنصر. ولكن هناك أيضًا خصائص وطرق مشتركة بينها ، لأن جميع فئات عقد DOM تشكل تسلسلًا هرميًا واحدًا.

تنتمي كل عقدة DOM إلى الفئة المضمنة المقابلة.

جذر التسلسل الهرمي هو [EventTarget] (https://dom.spec.whatwg.org/#eventtarget) ، الموروث بواسطة [Node] (http://dom.spec.whatwg.org/#interface-node ) ، وترث العقد الأخرى منه.

هذه هي الصورة والتفسيرات التي يجب اتباعها:

الclasses هي:

  • [EventTarget] (https://dom.spec.whatwg.org/#eventtarget) – هي فئة الجذر “المجردة”. لا يتم إنشاء كائنات هذه الفئة أبدًا. إنه بمثابة قاعدة ، بحيث تدعم جميع عقد DOM ما يسمى “الأحداث” ، وسندرسها لاحقًا.
  • [Node] (http://dom.spec.whatwg.org/#interface-node) – هي أيضًا فئة “مجردة” ، تعمل كقاعدة لعقد DOM. يوفر وظائف الشجرة الأساسية: motherNode وnextSibling وchildNodes وما إلى ذلك (فهي عبارة عن حروف). لا يتم إنشاء كائنات فئة “العقدة” مطلقًا. ولكن هناك فئات عقدة محددة ترث منه ، وهي: Text للعقد النصية وElement لعقد العناصر والمزيد من الأنواع الغريبة مثل Comment لعقد التعليق.
  • [Element] (http://dom.spec.whatwg.org/#interface-element) – هي فئة أساسية لعناصر DOM. يوفر التنقل على مستوى العنصر مثل nextElementSibling وchildren وطرق البحث مثل getElementsByTagName وquerySelector. لا يدعم المتصفح HTML فحسب ، بل يدعم أيضًا XML و SVG. تعمل فئة Element كقاعدة لفئات أكثر تحديدًا:SVGElement و XMLElement وHTMLElement.
  • [HTMLElement] (https://html.spec.whatwg.org/multipage/dom.html#htmlelement) – أخيرًا هو الفصل الأساسي لجميع عناصر HTML. يتم توريثه بواسطة عناصر HTML محددة:     – [HTMLInputElement] (https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) – فئة عناصر <input> ،     – [HTMLBodyElement] (https://html.spec.whatwg.org/multipage/semantics.html#htmlbodyelement) – فئة عناصر <body> ،     – [HTMLAnchorElement] (https://html.spec.whatwg.org/multipage/semantics.html#htmlanchorelement) – فئة عناصر "` ،     – … وهكذا ، كل علامة لها فئة خاصة بها قد توفر خصائص وأساليب معينة.

لذلك ، فإن المجموعة الكاملة من الخصائص والأساليب لعقدة معينة تأتي نتيجة الميراث.

على سبيل المثال ، لنفكر في كائن DOM لعنصر <input>. وهي تنتمي إلى فئة [HTMLInputElement] (https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement).

يحصل على خصائص وأساليب تراكب (مدرج في ترتيب الميراث):

  • “HTMLInputElement” – توفر هذه الفئة خصائص خاصة بالإدخال ،
  • HTMLElement – يوفر طرق عنصر HTML الشائعة (والرسائل / المحددات) ،
  • “العنصر” – يوفر طرق العناصر العامة ،
  • العقدة – توفر خصائص عقدة DOM الشائعة ،
  • EventTarget – يقدم الدعم للأحداث (التي سيتم تغطيتها) ،
  • … وأخيرًا يرث من Object ، لذلك تتوفر أيضًا طرق" الكائن العادي "مثلhasOwnProperty.

لرؤية اسم فئة عقدة DOM ، يمكننا أن نتذكر أن الكائن عادة ما يكون له خاصية المنشئ. وهي تشير إلى مُنشئ الصنف ، و buildor.name هو اسمه:

alert(document.body.constructor.name); // HTMLBodyElement

…Or we can just toString it:

alert(document.body); // [object HTMLBodyElement]

We also can use instanceof to check the inheritance:

alert(document.body instanceof HTMLBodyElement); // true
alert(document.body instanceof HTMLElement); // true
alert(document.body instanceof Element); // true
alert(document.body instanceof Node); // true
alert(document.body instanceof EventTarget); // true

كما نرى ، فإن عقد DOM هي كائنات JavaScript عادية. يستخدمون الفصول القائمة على النموذج الأولي للميراث.

من السهل أيضًا رؤية ذلك عن طريق إخراج عنصر باستخدام “console.dir (elem)” في المستعرض. هناك في وحدة التحكم يمكنك مشاهدة HTMLElement.prototype وElement.prototype وما إلى ذلك.

``smart header=" console.dir (elem)مقابلconsole.log (elem) "" تدعم معظم المتصفحات أمرين في أدوات المطورين الخاصة بهم:console.logو console.dir`. يخرجون حججهم إلى وحدة التحكم. بالنسبة لكائنات JavaScript ، تقوم هذه الأوامر بنفس الشيء.

ولكن بالنسبة لعناصر DOM فهي مختلفة:

  • يُظهر console.log (elem) عنصر شجرة DOM.
  • يُظهر console.dir (elem) العنصر كعنصر DOM ، جيد لاستكشاف خصائصه.

جربه على document.body.

````smart header="IDL in the spec"
في المواصفات ، لا يتم وصف فئات DOM باستخدام JavaScript ، ولكن [لغة وصف واجهة خاصة] (https://en.wikipedia.org/wiki/Interface_description_language) (IDL) ، يسهل فهمها عادةً.

في IDL ، يتم إلحاق جميع الخصائص بأنواعها. على سبيل المثال ، "DOMString" و "boolean" وما إلى ذلك.

إليك مقتطف منه ، مع التعليقات:

```js
// تعريف HTMLInputElement
*! *
// النقطتين ":" تعني أن HTMLInputElement يرث من HTMLElement
* /! *
واجهة HTMLInputElement: HTMLElement {
   // here انتقل إلى خصائص وأساليب عناصر <input>

*! *
   // "DOMString" يعني أن قيمة الخاصية هي سلسلة
* /! *
   السمة DOMString تقبل ؛
   سمة DOMString alt ؛
   سمة الإكمال التلقائي لـ DOMString ؛
   قيمة DOMString ؛

*! *
   // خاصية القيمة المنطقية (صواب / خطأ)
   خاصية التركيز التلقائي المنطقي ؛
* /! *
   ...
*! *
   // now the method: يعني "void" أن الطريقة لا تُرجع أي قيمة
*/!*
  void select();
  ...
}
## خاصية "nodeType"

توفر خاصية `nodeType` طريقة أخرى" قديمة الطراز "للحصول على" نوع "عقدة DOM.

لها قيمة رقمية:
- `elem.nodeType == 1` لعقد العناصر ،
- `elem.nodeType == 3` للعقد النصية ،
- `elem.nodeType == 9` لكائن المستند ،
- هناك عدد قليل من القيم الأخرى في [المواصفات] (https://dom.spec.whatwg.org/#node).

على سبيل المثال:

```html run
<body>
  <script>
  let elem = document.body;

  // let's examine what it is?
  alert(elem.nodeType); // 1 => element

  // and the first child is...
  alert(elem.firstChild.nodeType); // 3 => text

  // for the document object, the type is 9
  alert( document.nodeType ); // 9
  </script>
</body>
```

في النصوص الحديثة ، يمكننا استخدام "مثيل" والاختبارات الأخرى القائمة على الفصل لرؤية نوع العقدة ، ولكن في بعض الأحيان قد يكون "نوع العقدة" أبسط. يمكننا فقط قراءة `nodeType` ، وليس تغييره.

## العلامة: nodeName و tagName

بالنظر إلى عقدة DOM ، يمكننا قراءة اسم علامتها من خصائص `nodeName` أو` tagName`:

على سبيل المثال:

تشغيل شبيبة
تنبيه (document.body.nodeName) ؛ // الجسم
تنبيه (document.body.tagName) ؛ // الجسم
``

هل هناك فرق بين `tagName` و` nodeName`؟

بالتأكيد ، ينعكس الفرق في أسمائهم ، لكنه في الواقع خفي قليلاً.

- خاصية `tagName` موجودة فقط لعقد` العنصر`.
- يُعرّف "nodeName" لأي "عقدة":
    - للعناصر يعني نفس "tagName".
    - لأنواع العقد الأخرى (نص ، تعليق ، إلخ.) تحتوي على سلسلة بنوع العقدة.

بمعنى آخر ، لا يتم دعم `tagName` إلا بعقد العناصر (لأنها تنشأ من فئة` Element`) ، بينما يمكن لـ `nodeName` أن يقول شيئًا عن أنواع العقد الأخرى.

على سبيل المثال ، دعنا نقارن `tagName` و` nodeName` لـ `المستند` وعقدة التعليق:

```html run
<body><!-- comment -->

  <script>
    // for comment
    alert( document.body.firstChild.tagName ); // undefined (not an element)
    alert( document.body.firstChild.nodeName ); // #comment

    // for document
    alert( document.tagName ); // undefined (not an element)
    alert( document.nodeName ); // #document
  </script>
</body>
```

إذا تعاملنا فقط مع العناصر ، فيمكننا استخدام كل من "tagName" و "nodeName" - فلا فرق.

"` `عنوان مختصر وذكي=" اسم العلامة دائمًا ما يكون بحروف كبيرة إلا في وضع XML "
يحتوي المتصفح على وضعين لمعالجة المستندات: HTML و XML. عادة ما يتم استخدام وضع HTML لصفحات الويب. يتم تمكين وضع XML عندما يتلقى المتصفح مستند XML مع الرأس: `Content-Type: application / xml + xhtml`.

في وضع HTML ، يتم دائمًا تمييز "tagName / nodeName" بأحرف كبيرة: إنه `BODY` إما لـ` <body> `أو` <BoDy> `.

في وضع XML يتم الاحتفاظ بالحالة "كما هي". في الوقت الحاضر نادرا ما يستخدم وضع XML.
``


## innerHTML: المحتويات

The [innerHTML](https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin) property allows to get the HTML inside the element as a string.

يمكننا أيضًا تعديله. لذا فهي واحدة من أقوى الطرق لتغيير الصفحة.

يوضح المثال محتويات `document.body` ثم يستبدلها بالكامل:

```html run
<body>
  <p>A paragraph</p>
  <div>A div</div>

  <script>
    alert( document.body.innerHTML ); // read the current contents
    document.body.innerHTML = 'The new BODY!'; // replace it
  </script>

</body>
```

يمكننا محاولة إدراج HTML غير صالح ، سيقوم المتصفح بإصلاح أخطاءنا:

```html run
<body>

  <script>
    document.body.innerHTML = '<b>test'; // forgot to close the tag
    alert( document.body.innerHTML ); // <b>test</b> (fixed)
  </script>

</body>
```

```عنوان مختصر= "البرامج النصية لا تنفذ"
إذا أدرج `innerHTML` علامة` <script> `في المستند - يصبح جزءًا من HTML ، ولكن لا يتم تنفيذه.
```

### احذر: "innerHTML + =" يقوم باستبدال كامل

يمكننا إلحاق HTML بعنصر باستخدام `elem.innerHTML + =" more html "`.

مثله:

```js
chatDiv.innerHTML += "<div>Hello<img src='smile.gif'/> !</div>";
chatDiv.innerHTML += "How goes?";
```

ولكن يجب أن نكون حذرين للغاية بشأن القيام بذلك ، لأن ما يحدث هو * ليس * إضافة ، ولكن استبدال كامل.

من الناحية الفنية ، يفعل هذان الخطان نفس الشيء:

```js
elem.innerHTML += "...";
// is a shorter way to write:
elem.innerHTML = elem.innerHTML + "..."
```

بمعنى آخر ، يقوم `innerHTML + =` بذلك:

1. تتم إزالة المحتويات القديمة.
2. بدلاً من ذلك ، يتم كتابة "innerHTML" الجديد (سلسلة من القديم والجديد).

** نظرًا لأن المحتوى "خالي من أي شيء" وأعيد كتابته من البداية ، فسيتم إعادة تحميل جميع الصور والموارد الأخرى **.

في مثال `chatDiv` أعلى السطر` chatDiv.innerHTML + = "كيف الحال؟" `` يعيد إنشاء محتوى HTML ويعيد تحميل `smile.gif` (آمل أن يتم تخزينه مؤقتًا). إذا كان `chatDiv` يحتوي على الكثير من النصوص والصور الأخرى ، فإن إعادة التحميل تصبح مرئية بوضوح.

هناك آثار جانبية أخرى أيضًا. على سبيل المثال ، إذا تم تحديد النص الحالي بالماوس ، فإن معظم المتصفحات ستزيل التحديد عند إعادة كتابة `innerHTML`. وإذا كان هناك "<input>" مع نص أدخله الزائر ، فسيتم إزالة النص. وما إلى ذلك وهلم جرا.

لحسن الحظ ، هناك طرق أخرى لإضافة HTML إلى جانب "innerHTML" ، وسندرسها قريبًا.

## outerHTML: HTML الكامل للعنصر

تحتوي الخاصية `outerHTML` على HTML الكامل للعنصر. هذا مثل `innerHTML` بالإضافة إلى العنصر نفسه.

إليك مثال:

```html run
<div id="elem">Hello <b>World</b></div>

<script>
  alert(elem.outerHTML); // <div id="elem">Hello <b>World</b></div>
</script>
```

** احذر: على عكس "innerHTML" ، لا تؤدي الكتابة إلى "outerHTML" إلى تغيير العنصر. بدلاً من ذلك ، يتم استبداله في DOM. **

نعم ، يبدو غريبًا ، وغريبًا ، لهذا السبب نقوم بعمل ملاحظة منفصلة عنه هنا. إلق نظرة.

تأمل في المثال:

```html run
<div>Hello, world!</div>

<script>
  let div = document.querySelector('div');

  // replace div.outerHTML with <p>...</p>
  div.outerHTML = '<p>A new element</p>'; // (*)

  // Wow! 'div' is still the same!
  alert(div.outerHTML); // <div>Hello, world!</div> (**)
</script>
```

تبدو غريبة حقا ، أليس كذلك؟

في السطر `(*)` استبدلنا `div` بـ` <p> عنصر جديد </ p> `. في المستند الخارجي (DOM) ، يمكننا رؤية المحتوى الجديد بدلاً من `<div>`. ولكن ، كما نرى في السطر `(**)` ، لم تتغير قيمة متغير `div` القديم!

لا يقوم تعديل "outerHTML" بتعديل عنصر DOM (الكائن المشار إليه ، في هذه الحالة ، المتغير 'div') ، ولكنه يزيله من DOM ويدرج HTML الجديد في مكانه.

ما حدث في `div.outerHTML = ...` هو:
- تمت إزالة `div` من المستند.
- تم إدراج جزء آخر من HTML "<p> عنصر جديد </ p>" في مكانه.
- `div` لا تزال لها قيمتها القديمة. لم يتم حفظ HTML الجديد في أي متغير.

من السهل جدًا ارتكاب خطأ هنا: قم بتعديل `div.outerHTML` ثم تابع العمل مع` div` كما لو كان به محتوى جديد فيه. لكنها لا تفعل ذلك. هذا الشيء صحيح بالنسبة لـ "innerHTML" ، ولكن ليس لـ "outerHTML".

يمكننا الكتابة إلى "elem.outerHTML" ، ولكن يجب أن نضع في اعتبارنا أنه لا يغير العنصر الذي نكتب إليه ("elem"). بدلاً من ذلك ، تضع HTML الجديد في مكانه. يمكننا الحصول على مراجع للعناصر الجديدة عن طريق الاستعلام عن DOM.

## nodeValue / data: محتوى عقدة النص

خاصية `innerHTML` صالحة لعقد العناصر فقط.

أنواع العقد الأخرى ، مثل العقد النصية ، لها نظيرها: خصائص `nodeValue` و` data`. هذان النوعان متشابهان تقريبًا للاستخدام العملي ، ولا توجد سوى اختلافات طفيفة في المواصفات. لذا سنستخدم "البيانات" لأنها أقصر.

مثال على قراءة محتوى العقدة النصية والتعليق:

```html run height="50"
<body>
  Hello
  <!-- Comment -->
  <script>
    let text = document.body.firstChild;
    alert(text.data); // Hello

    let comment = text.nextSibling;
    alert(comment.data); // Comment
  </script>
</body>
```

بالنسبة للعقد النصية ، يمكننا تخيل سبب لقراءتها أو تعديلها ، ولكن لماذا التعليقات؟

في بعض الأحيان يقوم المطورون بتضمين معلومات أو تعليمات قالب في HTML ، مثل هذا:

```html
<!-- if isAdmin -->
  <div>Welcome, Admin!</div>
<!-- /if -->
```

... ثم يمكن لجافا سكريبت قراءته من خاصية `البيانات` ومعالجة التعليمات المضمنة.

## textContent: نص خالص

يوفر `textContent` الوصول إلى * text * داخل العنصر: النص فقط ، ناقص جميع` <tags> `.

على سبيل المثال:

```html run
<div id="news">
  <h1>Headline!</h1>
  <p>Martians attack people!</p>
</div>

<script>
  // Headline! Martians attack people!
  alert(news.textContent);
</script>
```

كما نرى ، يتم إرجاع النص فقط ، كما لو تم قطع جميع `<tags>` ، لكن النص فيها بقي.

من الناحية العملية ، نادرًا ما تكون هناك حاجة لقراءة مثل هذا النص.

** تعد الكتابة إلى "textContent" أكثر فائدة لأنها تتيح لك كتابة النص "بطريقة آمنة". **

لنفترض أن لدينا سلسلة عشوائية ، على سبيل المثال تم إدخالها من قبل مستخدم ، ونريد إظهارها.

- باستخدام "innerHTML" ، سنقوم بإدراج "كـ HTML" ، مع كافة علامات HTML.
- مع "textContent" سنقوم بإدراج "كنص" ، يتم التعامل مع جميع الرموز حرفياً.

قارن بين الاثنين:

```html run
<div id="elem1"></div>
<div id="elem2"></div>

<script>
  let name = prompt("What's your name?", "<b>Winnie-the-Pooh!</b>");

  elem1.innerHTML = name;
  elem2.textContent = name;
</script>
```

1. The first `<div>` gets the name "as HTML": all tags become tags, so we see the bold name.
2. The second `<div>` gets the name "as text", so we literally see `<b>Winnie-the-Pooh!</b>`.

في معظم الحالات ، نتوقع النص من مستخدم ونريد معاملته كنص. لا نريد HTML غير متوقع في موقعنا. يؤدي التعيين إلى `textContent` ذلك بالضبط.

## خاصية "مخفية"

تحدد السمة "مخفي" وخاصية DOM ما إذا كان العنصر مرئيًا أم لا.

We can use it in HTML or assign it using JavaScript, like this:

```html run height="80"
<div>Both divs below are hidden</div>

<div hidden>With the attribute "hidden"</div>

<div id="elem">JavaScript assigned the property "hidden"</div>

<script>
  elem.hidden = true;
</script>
```

من الناحية الفنية ، يعمل `المخفي` تمامًا مثل` style = "display: none" `. لكنها أقصر في الكتابة.

إليك عنصر وامض:

```html run height=50
<div id="elem">A blinking element</div>

<script>
  setInterval(() => elem.hidden = !elem.hidden, 1000);
</script>
```

## المزيد من الخصائص

تحتوي عناصر DOM أيضًا على خصائص إضافية ، لا سيما تلك التي تعتمد على الفئة:

- `القيمة` - قيمة` <input> `و` <select> `و` <textarea>` (`HTMLInputElement`،` HTMLSelectElement` ...).
- `href` -" href "لـ` <a href="..."> `(` HTMLAnchorElement`).
- `id` - قيمة السمة" id "، لجميع العناصر (` HTMLElement`).
- ...وأكثر بكثير...

على سبيل المثال:

```html run height="80"
<input type="text" id="elem" value="value">

<script>
  alert(elem.type); // "text"
  alert(elem.id); // "elem"
  alert(elem.value); // value
</script>
```

معظم سمات HTML القياسية لها خاصية DOM المقابلة ، ويمكننا الوصول إليها بهذه الطريقة.

إذا أردنا معرفة القائمة الكاملة للخصائص المدعومة لفئة معينة ، فيمكننا العثور عليها في المواصفات. على سبيل المثال ، يتم توثيق `HTMLInputElement` على <https://html.spec.whatwg.org/#htmlinputelement>.

أو إذا كنا نرغب في الحصول عليهم بسرعة أو مهتمون بمواصفات متصفح محددة - يمكننا دائمًا إخراج العنصر باستخدام `console.dir (elem)` وقراءة الخصائص. أو استكشف "خصائص DOM" في علامة التبويب "العناصر" في أدوات مطور المتصفح.

## ملخص

تنتمي كل عقدة DOM إلى فئة معينة. تشكل الفصول هرمية. مجموعة كاملة من الخصائص والأساليب تأتي نتيجة الميراث.

خصائص عقدة DOM الرئيسية هي:

`nodeType`
: يمكننا استخدامه لمعرفة ما إذا كانت العقدة عبارة عن نص أو عقدة عنصر. يحتوي على قيمة رقمية: `1` للعناصر ،` 3` للعقد النصية ، وبعض العناصر الأخرى لأنواع العقد الأخرى. يقرأ فقط.

`nodeName / tagName`
: للعناصر ، اسم العلامة (أحرف كبيرة ما لم يكن وضع XML). بالنسبة إلى العقد غير العنصر ، يصف `nodeName` ما هو. يقرأ فقط.

`innerHTML`
: محتوى HTML للعنصر. يمكن تعديله.

`outerHTML`
: HTML الكامل للعنصر. لا تلمس عملية الكتابة في `elem.outerHTML`` elem` نفسها. بدلاً من ذلك ، يتم استبداله بـ HTML الجديد في السياق الخارجي.

`nodeValue / data`
: محتوى عقدة غير عنصر (نص ، تعليق). هذان النوعان متشابهان تقريبًا ، وعادة ما نستخدم `البيانات '. يمكن تعديله.

`textContent`
: النص الموجود داخل العنصر: HTML ناقص جميع `<tags>`. تؤدي الكتابة فيه إلى وضع النص داخل العنصر ، مع معاملة جميع الأحرف والعلامات الخاصة كنص. يمكن إدراج النص الذي ينشئه المستخدم بأمان والحماية من إدخالات HTML غير المرغوب فيها.

"مخفي"
: عند التعيين على "true" ، يتم عرض CSS `display: none`.

تحتوي عقد DOM أيضًا على خصائص أخرى بناءً على فئتها. على سبيل المثال ، عناصر `<input>` (`HTMLInputElement`) تدعم` القيمة` ، `النوع` ، في حين أن` <a> العناصر (`HTMLAnchorElement`) تدعم` href` إلخ. معظم سمات HTML القياسية لها خاصية DOM مقابلة .

ومع ذلك ، فإن خصائص HTML وخصائص DOM ليست هي نفسها دائمًا ، كما سنرى في الفصل التالي.

مهمه

هناك شجرة منظمة على أنها متداخلة ul / li.

اكتب الرمز الذي يظهر لكل <li> ما يلي:

  1. ما هو النص الموجود بداخله (بدون الشجرة الفرعية)
  2. عدد “
  3. ” المتداخلة – جميع الأحفاد ، بما في ذلك المتداخلون بعمق. [demo src=“solution”]

افتح sandbox للمهمه.

لنقم بعمل iteration علي <li>:

for (let li of document.querySelectorAll('li')) {
  ...
}

في الحلقة ، نحتاج إلى إدخال النص داخل كل “li”.

يمكننا قراءة النص من العقدة الفرعية الأولى لـ li ، وهي العقدة النصية:

for (let li of document.querySelectorAll('li')) {
  let title = li.firstChild.data;

  // title is the text in <li> before any other nodes
}

ثم يمكننا الحصول على عدد الchildren items li.getElementsByTagName('li').length.

افتح الحل في sandbox.

ماذا يظهر النص؟

<html>

<body>
  <script>
    alert(document.body.lastChild.nodeType);
  </script>
</body>

</html>

هناك صيد هنا.

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

لذلك تكون النتيجة 1 (عقدة العنصر).

<html>

<body>
  <script>
    alert(document.body.lastChild.nodeType);
  </script>
</body>

</html>

ماذا يبين هذا الكود؟

<script>
  let body = document.body;

  body.innerHTML = "<!--" + body.tagName + "-->";

  alert( body.firstChild.data ); // what's here?
</script>

الإجابة: BODY.

<script>
  let body = document.body;

  body.innerHTML = "<!--" + body.tagName + "-->";

  alert( body.firstChild.data ); // BODY
</script>

ما يحدث خطوة بخطوة:

  1. يتم استبدال محتوى “” بالتعليق. التعليق هو <! - BODY -> ، لأن body.tagName ==" BODY ". كما نتذكر ، فإن tagName دائمًا ما تكون أحرفًا كبيرة بتنسيق HTML.
  2. التعليق هو الآن العقدة الفرعية الوحيدة ، لذلك نحصل عليه في body.firstChild.
  3. خاصية “البيانات” للتعليق هي محتوياته (داخل <! --...-->): “” BODY "`.

إلى أي فئة ينتمي “المستند”؟

ما مكانها في التسلسل الهرمي لـ DOM؟

هل ترث من “العقدة” أو “العنصر” ، أو ربما “HTMLElement”؟

Wيمكننا معرفة أي فئة ينتمي إليها بإخراجها ، مثل:

تشغيل شبيبة تنبيه (وثيقة) ؛ // [كائن HTMLDocument] ``

أو:

تشغيل شبيبة تنبيه (document.constructor.name) ؛ // HTMLDocument ``

لذا ، المستند هو مثيل لفئةHTMLDocument.

ما مكانها في التسلسل الهرمي؟

نعم ، يمكننا تصفح المواصفات ، ولكن سيكون من الأسرع معرفة ذلك يدويًا.

دعنا نجتاز سلسلة النموذج عبر “proto”.

كما نعلم ، فإن طرق الصف موجودة في “النموذج الأولي” للمنشئ. على سبيل المثال ، يحتوي “HTMLDocument.prototype” على طرق للمستندات.

أيضًا ، هناك إشارة إلى وظيفة المُنشئ داخل النموذج الأولي:

تشغيل شبيبة تنبيه (HTMLDocument.prototype.constructor === HTMLDocument) ؛ // صحيح ``

للحصول على اسم الفئة كسلسلة ، يمكننا استخدام buildor.name. لنفعل ذلك من أجل سلسلة النموذج “المستند” بالكامل ، حتى الفئة “العقدة”:

تشغيل شبيبة تنبيه (HTMLDocument.prototype.constructor.name) ؛ // HTMLDocument تنبيه (HTMLDocument.prototype .__ proto__.constructor.name) ؛ // المستند تنبيه (HTMLDocument.prototype .__ proto__.proto.constructor.name) ؛ // العقدة ``

هذا هو التسلسل الهرمي.

يمكننا أيضًا فحص الكائن باستخدام console.dir (مستند) ورؤية هذه الأسماء من خلال فتح “proto”. تأخذهم وحدة التحكم من المنشئ داخليًا.

خريطة الدورة التعليمية