Реализация document.getElementById в javascript

Я пытаюсь реализовать собственный document.getElementById в javascript. Я реализовал document.getElementsByClassName в javascript.

function getElementsByClassName (className) {
  var nodeList = [];
  function test(node) {
      if (node.classList && node.classList.contains(className)) {
        nodeList.push(node);
      }
      
      for (var index = 0; index < node.childNodes.length; index++) {
        test(node.childNodes[index]);
      }
      
      return nodeList;
  }
  
    test(document.body);
    
  return nodeList;
};

// Fails here.
function getElementById(className) {
    const result = [];
    
    function getEachIDNode(node) {
        if (node.contains(className)) {
            return node;
        }

        for(let i=0; i<node.childNodes.length; i++) {
            getEachIDNode(node.childNodes[i]);
        }

    }

    getEachIDNode(document.body);
}

console.info(getElementsByClassName('winner'));
console.info(getElementById('test'));
  <table>      
        <tr id = "test">
            <td>#</td>
            <td class = "winner">aa</td>
            <td>bb</td>
            <td>cc</td>
            <td>dd</td>
        </tr>
   </table>

   <table>      
        <tr>
            <td>#</td>
            <td class = "winner">aa</td>
            <td>bb</td>
            <td>cc</td>
            <td>dd</td>
        </tr>
   </table>

   <table>      
        <tr>
            <td>#</td>
            <td class = "winner">dd</td>
            <td>cc</td>
            <td>bb</td>
            <td>aa</td>
        </tr>
   </table>

Я пытаюсь понять, как я могу проверить, есть ли у узла идентификатор атрибута.

Может кто меня просветить?

также добавьте свой html-код, а также, если возможно, предоставьте исполняемый код

Vikasdeep Singh 24.07.2018 06:36

Вы можете напрямую проверить node.id === className. Хотя, className - странное название аргумента для getElementById.

31piy 24.07.2018 06:36

@VicJordan готово. пожалуйста, проверьте. я добавил свою реализацию.

TechnoCorner 24.07.2018 06:39
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
3
1 332
4

Ответы 4

Сравните свойство id узла с переданным аргументом (возможно, лучше использовать id в качестве аргумента, а не className):

function getElementById(id) {
    const result = [];

    function getEachIDNode(node) {
        if (node.id === id) {
            result.push(node);
        }
        for(let i=0; i<node.childNodes.length; i++) {
            getEachIDNode(node.childNodes[i]);
        }
    }
    getEachIDNode(document.body);
    return result;
}
console.info(getElementById('subchild')[0].innerHTML);
<div id = "parent">
  <div id = "child1">
  </div>
  <div id = "child2">
    <div id = "subchild">
      subchild!
    </div>
  </div>
</div>

Но если вы фактически хотите реплицировать getElementById, не пытайтесь вернуть массив, верните один элемент :

function getElementById(id) {
  let match = null;
  const doFind = node => {
    if (!match && node.id === id) match = node;
    if (!match) return [...node.childNodes].find(doFind);
  }
  doFind(document.body);
  return match;
}
console.info(getElementById('subchild').innerHTML);
<div id = "parent">
  <div id = "child1">
  </div>
  <div id = "child2">
    <div id = "subchild">
      subchild!
    </div>
  </div>
</div>

Любопытный вопрос: зачем нам нужен массив результатов, если мы знаем, что идентификатор уникален? не можем ли мы вернуться напрямую из оператора if?

TechnoCorner 24.07.2018 06:41

Да, было бы лучше вернуть один элемент, если вы действительно хотите воспроизвести getElementById. Массив здесь не имеет особого смысла (была ли причина, по которой вы пытались его использовать?)

CertainPerformance 24.07.2018 06:45

Ах, не совсем так. Позже я повторно просматривал свой код, и тогда у меня возникла эта мысль! Спасибо за Ваш ответ.

TechnoCorner 24.07.2018 06:46

@TechnoCorner, пожалуйста, не забудьте принять и проголосовать за ответ, если вы сочтете его полезным.

Vikasdeep Singh 24.07.2018 08:56

Проверить свойство атрибута элемента DOM.

function getElementById(id) {
    const result = [];

    function getEachIDNode(node) {
        if (!(node instanceof HTMLElement))
            return;

        if (node.hasAttribute('id') && node.getAttribute('id') === id) {
            result.push(node);
        }

        for(let i=0; i<node.childNodes.length; i++) {
            if (result.length > 0)
                return;
            getEachIDNode(node.childNodes[i]);
        }

    }
    getEachIDNode(document.body);
    return result[0];
}

Значит, элементы <svg> и их дочерние элементы исключены?

Kaiido 24.07.2018 07:35

Никакие <svg> не выполняются, поскольку <svg> не являются instanceof HTMLElement.

Akki 24.07.2018 07:53

Собственный document.getElementById не просматривает дерево DOM в поисках вашего Элемента, и поэтому он быстрее, чем другие методы выбора DOM.

Действительно, браузеры должны хранить своего рода хеш-карту всех элементов с идентификатором в активном документе. Таким образом, они просто просматривают этот хеш-карта (который не является одним из них) и возвращают элемент, если они его нашли.

Благодаря IE </irony> они действительно предоставляют некоторые записи этого хеш-карта как свойства глобального объекта window.

Поэтому, если вы собираетесь создать свою собственную реализацию, вы можете сначала проверить, возвращает ли это свойство ваш Element.
К сожалению, может случиться так, что идентификатор элемента действительно совпадает с другим свойством объекта window. Так что может случиться так, что мы все же нужно пройти DOM.
В этом случае используйте TreeWalker, который представляет собой самый быстрый API, который мы должны пройти по дереву DOM, более того, когда нас интересуют только некоторые типы узлов (здесь элементы).

В общем, лучшая реализация могла бы выглядеть так:

function getElementById(id) {
  if (!(id in window)) {
    console.info(id, 'not found');
    return null; // we are sure it's not set
  }
  // id maps are not marked as 'own property'
  if (!window.hasOwnProperty(id)) {
    if (window[id] instanceof Element &&
      window[id].id === id) { // it's our Element
      console.info(id, 'found in window');
      return window[id];
    }
    // in case of duplicate window[id] should return an HTMLCollection
    // (IIRC only Chrome does it correctly though)
    if (window[id] instanceof HTMLCollection &&
      window[id][0].id === id) {
      console.info(id, 'duplicate id is bad');
      return window[id][0];
    }
  }
  console.info(id, 'walking...');
  var walker = document.createTreeWalker(
    document.documentElement,
    NodeFilter.SHOW_ELEMENT,
    null,
    false
  );
  while (walker.nextNode()) {
    if (walker.currentNode.id === id) {
      return walker.currentNode;
    }
  }
  return null;
}
console.info(getElementById('foo'));
console.info(getElementById('unique'));
console.info(getElementById('duplicate'));
window.overwritten = 'oups';
console.info(getElementById('overwritten'));
<div id = "unique">
  <div id = "duplicate"></div>
  <div id = "duplicate"></div>
  <div id = "overwritten"></div>
</div>

Как видите, в этой реализации мы просматриваем DOM только в том случае, если для свойства окна установлено другое значение, что значительно улучшает производительность.

Чтобы проверить, есть ли у узла идентификатор атрибута, вы должны написать вот так:

            var attr_check = $(".selector").attr('id')                              
            if (attr_check != undefined || attr_check != false)
            {
                console.info("this element has attribute id")
            }

Вы также пишете этот код:

           var attr_check = document.getElementById('div-id').attr('id')    

вместо этого:

           var attr_check = $(".selector").attr('id')   

Другие вопросы по теме