如何优化像"this.parentNode.parentNode.parentNode ..."这样的代码?

yao*_*qkl 16 javascript

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();
};
Run Code Online (Sandbox Code Playgroud)

如您所见,我的代码中有一部分是这样的:

this.parentNode.parentNode.parentNode.parentNode;  
Run Code Online (Sandbox Code Playgroud)

有没有其他方法来优化代码(不使用jQuery)?

han*_*aad 32

您可以使用非递归辅助函数,例如:

function nthParent(element, n) {
  while(n-- && element)  
    element = element.parentNode;
  return element;
}
Run Code Online (Sandbox Code Playgroud)


mad*_*ox2 27

您可以使用递归辅助函数,例如:

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

var child = getNthParent(someElement, 4);
Run Code Online (Sandbox Code Playgroud)

  • @yaochiqkl`insters.callee`对我来说看起来有点麻烦.我会改用命名函数表达式.`var myFn = function getNthParent(elem,n){...}` (3认同)

Mon*_*pit 8

另一种方法


你的目标

根据您对原始问题的评论,您的总体目标是:

有一个博客列表.每个博客都有一个像"编辑"和"删除"的按钮.当我点击这样的按钮时,我想找到它的博客元素.

我相信解决您遇到的问题的最佳方法(而不是回答您提出的问题 - 抱歉!)是以不同的方式解决问题.

根据你的评论,你说你有这样的事情:

<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>
Run Code Online (Sandbox Code Playgroud)

您的目标是为每个项目clickbutton元素添加事件处理程序blog-link.

所以,让我们将这个目标从简单的英语翻译成伪代码:

for each `blog-link` `b`
  delete_button.onclick = delete_handler(`b`);
  edit_button.onclick = edit_handler(`b`);
Run Code Online (Sandbox Code Playgroud)

示例脚本

工作示例: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>
Run Code Online (Sandbox Code Playgroud)

说明

您选择实施解决方案的方式是有效的,但我认为我会给您一个不同的方式来查看同一个问题.

在我看来,blog实体的内部标签不应该知道周围HTML的结构或属性,以便你editdelete按钮工作.

您的原始解决方案必须从button父项链中的每一个向后工作,直到它找到它假设的正确的父元素,基于脆弱的方法,如N在父元素链中向上移动时间的硬编码.如果我们能够使用普通的JavaScript元素选择来绝对确定我们选择的内容,那会不会更好?这样,无论HTML结构如何变化,只要类和ID保持一致,我们的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);
  }
});
Run Code Online (Sandbox Code Playgroud)

对于数组中的每个deleteButton元素,我们为事件处理程序分配一个匿名函数onclick.创建这个匿名函数允许我们创建一个闭包.

这意味着每个deleteButton.onclick函数将单独"记住" blogitem它所属的属性.

查看关于闭包的SO问题/答案了解更多信息:JavaScript闭包如何工作?

我们抛出HTMLCollection.prototype.forEach...一行来为forEach所有HTMLCollection对象提供功能.函数如getElementsByClassName返回一个HTMLCollection对象.它在大多数情况下的行为与数组完全相同,但forEach默认情况下它不允许我们使用它.关于兼容性的注意事项:您当然可以使用标准for循环,因为forEach并非所有浏览器都可用(大多数旧版IE浏览器都应该受到指责).我更喜欢这个forEach成语.

最终结果

最终结果是代码稍微长一点,因为问题的范围比您实际提出的问题要宽一些.优点是此代码更灵活,并且不会被HTML结构的更改破坏.