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

时间:2016-02-01 11:43:48

标签: 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();
};

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

this.parentNode.parentNode.parentNode.parentNode;  

是否有另一种优化代码的方法(不使用jQuery)?

4 个答案:

答案 0 :(得分:33)

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

ckim@stph45:~/test/rtn5_fpga] make clean
at Makefile.inc RTEMS_API = @RTEMS_API@
rm -f a.out core mon.out gmon.out
rm -f -r 
rm -f -r  a.out *.o *.BAK Depends-o-optimize.tmp
rm -f -r o-optimize o-debug
rm -f -r o-optimize
rm -f init.c system.h config.h
ckim@stph45:~/prj/abts/rtems-qt/applications/sieve/rtn5_fpga] make
at Makefile.inc RTEMS_API = @RTEMS_API@
test -d o-optimize || mkdir o-optimize
ln -s ../src/init.c  init.c
sparc-ab-rtems-gcc --pipe -B/some/dir/path/lib/ -specs bsp_specs -qrtems   -Wall -I../../include -qnolinkcmds -T ../../lib/linkcmds.abtn5 -O4    -mtune=v8 -msoft-float -fcommon -DTARGET_ALDEBARAN       -c   -o o-optimize/init.o init.c
init.c:15:20: fatal error: system.h: No such file or directory
 #include "system.h"
                    ^
compilation terminated.
make: *** [o-optimize/init.o] Error 1

答案 1 :(得分:26)

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

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

var child = getNthParent(someElement, 4);

答案 2 :(得分: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>

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

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

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

示例脚本

工作示例: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的结构或属性,以便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);
  }
});

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

这意味着每个deleteButton.onclick函数都会单独“记住”它所属的blogitem

查看有关闭包的SO问题/答案以获取更多信息:How do JavaScript closures work?

我们引入HTMLCollection.prototype.forEach...行,为所有forEach个对象提供HTMLCollection功能。像getElementsByClassName这样的函数会返回HTMLCollection个对象。它在大多数情况下的行为与数组完全相同,但默认情况下它不允许我们使用forEach。关于兼容性的注意事项:您当然可以使用标准的for循环,因为forEach并非在所有浏览器中都可用(主要是旧版IE浏览器)。我更喜欢forEach成语。

最终结果

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

答案 3 :(得分:2)

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打印事件。 并在事件中找到这样的数组: enter image description here

我找到了我想要的元素:

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

它有效!多么神奇!也许事件代理是另一种方式! 谢谢大家的回答! 下次问问题之前,我会先考虑一下! :d