Как оптимизировать код типа "this.parentNode.parentNode.parentNode..."?

var topClick = function() {
  child = this.parentNode.parentNode.parentNode.parentNode;
  child.parentNode.removeChild(child);
  var theFirstChild = document.querySelector(".m-ctt .slt");
  data[child.getAttribute("data-id")].rank = 5;
  insertBlogs();
};

Как вы видите, есть часть моего кода:

this.parentNode.parentNode.parentNode.parentNode;  

Есть ли другой способ оптимизации кода (без использования jQuery)?

Ответы

Ответ 1

Альтернативный подход


Ваша цель

Согласно вашим комментариям по оригинальному вопросу, ваша общая цель такова:

Существует список блога. В каждом блоге есть кнопка, например "редактировать" и "удалять". Когда я нажимаю такие кнопки, я хочу найти элемент блога.

Я считаю, что лучший подход к решению проблемы, с которой вы столкнулись (в отличие от ответа на заданный вами вопрос - извините!), заключается в том, чтобы подойти к проблеме по-другому.

Из ваших комментариев вы сказали, что у вас есть что-то вроде этого:

<ul id="blog-list">
  <li class="blog-item">
    <a href="blog1.com">
      Boats galore!
    </a>
    <span class="blog-description">
      This is a blog about some of the best boats from Instagram.
    </span>
    <span class="blog-button delete-button">
      Delete
    </span>
    <span class="blog-button edit-button">
      Edit
    </span>
  </li>
  <li class="blog-item">
    <a href="blog2.com">
      Goats galore!
    </a>
    <span class="blog-description">
      A blog about the everyday adventures of goats in South Africa.
    </span>
    <span class="blog-button delete-button">
      Delete
    </span>
    <span class="blog-button edit-button">
      Edit
    </span>
  </li>
  <li class="blog-item">
    <a class="blog-link" href="blog3.com">
      Totes galore!
    </a>
    <span class="blog-description">
      A blog about containers and bags, and the owners who love them.
    </span>
    <span class="blog-button delete-button">
      Delete
    </span>
    <span class="blog-button edit-button">
      Edit
    </span>
  </li>
</ul>

И ваша цель состоит в том, чтобы добавить click обработчики событий в элементы button для каждого элемента blog-link.

Итак, позвольте просто перевести эту цель с простого английского на псевдокод:

for each `blog-link` `b`
  delete_button.onclick = delete_handler(`b`);
  edit_button.onclick = edit_handler(`b`);

Пример script

Рабочий пример: http://jsfiddle.net/vbt6bjwy/10/

<script>
  function deleteClickHandler(event, parent) {
    event.stopPropagation();
    parent.remove();
  }

  function editClickHandler(event, parent) {
    event.stopPropagation();
    var description = parent.getElementsByClassName("blog-description")[0];
    description.innerHTML = prompt("Enter a new description:");
  }

  function addClickHandlers() {
    var bloglistElement = document.getElementById("blog-list");
    var blogitems = bloglistElement.getElementsByClassName("blog-item");

    blogitems.forEach(function(blogitem){
      var deleteButtons = blogitem.getElementsByClassName("delete-button");

      deleteButtons.forEach(function(deleteButton){
        deleteButton.onclick = function(event) {
          return deleteClickHandler(event, blogitem);
        }
      });

      var editButtons = blogitem.getElementsByClassName("edit-button");

      editButtons.forEach(function(editButton){
        editButton.onclick = function(event) {
          return editClickHandler(event, blogitem);
        }
      });
    });
  }

  HTMLCollection.prototype.forEach = Array.prototype.forEach;
  addClickHandlers();
</script>

Объяснение

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

На мой взгляд, внутренние теги объекта blog не должны иметь знания о структуре или свойствах окружающего HTML для ваших кнопок edit и delete.

Ваше исходное решение должно работать в обратном направлении от каждой button до цепочки родителей, пока не найдет то, что оно предполагает, является правильным родительским элементом, основанным на хрупком методе, таком как жесткое кодирование, продвигающееся N раз в цепочке из родительских элементов. Не было бы лучше, если бы мы могли использовать обычный выбор элементов JavaScript, чтобы быть абсолютно уверенными в том, что мы выбираем? Таким образом, независимо от того, как может измениться структура HTML, наш JavaScript не будет прерываться до тех пор, пока классы и идентификаторы остаются согласованными.

Это решение выполняет итерацию по каждому blog-item в элементе #blog-list:

blogitems.forEach(function(blogitem){ ... });

В цикле forEach мы захватываем массивы, содержащие элементы .delete-button и .edit-button. В каждом из этих элементов мы добавляем соответствующий обработчик события к свойству onclick:

deleteButtons.forEach(function(deleteButton){
  deleteButton.onclick = function(event) {
    return deleteClickHandler(event, blogitem);
  }
});

Для каждого элемента deleteButton в массиве мы назначаем анонимную функцию обработчику событий onclick. Создание этой анонимной функции позволяет нам создать закрытие.

Это означает, что каждая функция deleteButton.onclick будет индивидуально "помнить", к которой blogitem принадлежит.

Ознакомьтесь с этим вопросом/ответом о закрытии для получения дополнительной информации: Как работают блокировки JavaScript?

И мы добавляем строку HTMLCollection.prototype.forEach..., чтобы обеспечить функциональность forEach всем объектам HTMLCollection. Такие функции, как getElementsByClassName, возвращают объект HTMLCollection. Он действует как массив по большей части, но по умолчанию он не позволяет нам использовать forEach. Заметка о совместимости: вы можете использовать стандартный цикл for, поскольку forEach недоступен во всех браузерах (в основном виноваты старые браузеры IE). Я предпочитаю идиому forEach.

Конечный результат

Конечный результат - это немного более длинный код, поскольку объем проблемы немного шире, чем вопрос, который вы действительно задали. Преимущество в том, что этот код гораздо более гибкий и устойчивый к нарушению изменений в структуре HTML.

Ответ 2

Вы можете использовать нерекурсивную вспомогательную функцию, например:

function nthParent(element, n) {
  while(n-- && element)  
    element = element.parentNode;
  return element;
}

Ответ 3

Вы можете использовать рекурсивную вспомогательную функцию, например:

function getNthParent(elem, n) {
    return n === 0 ? elem : getNthParent(elem.parentNode, n - 1);
}

var child = getNthParent(someElement, 4);

Ответ 4

var topClick = function(event){
    console.log(event);
    child = this.parentNode.parentNode.parentNode.parentNode;
    child.parentNode.removeChild(child);
    var theFirstChild = document.querySelector(".m-ctt .slt");
    data[child.getAttribute("data-id")].rank = 5;
    insertBlogs();
};

Сюрприз! Я печатаю событие через console.log. И найдите такой массив внутри события: введите описание изображения здесь

И я нахожу элемент, который мне нужен:

function(event){
console.log(event.path[4]);
child = event.path[4];
}

и он работает! Как волшебство! Возможно, агент событий - это еще один способ!
Спасибо вам все же за ответы! В следующий раз, прежде чем задавать вопросы, я сначала подумаю!: D