使用递归从头开始实现 getElementByClassName

Implement getElementByClassName from scratch using recursion

我有提示构建一个函数,它是 getElementByClassName,使用 document.bodyelement.classListelement.childNodes AND 递归。 这就是我的 :

var getElementsByClassName = function(className
) {
  var classNameArray = [];
  var bodyElement = document.body;
  var traverseTheNode = function(elementNode) {
    if (elementNode.classList.contains(className)) {
      classNameArray.push(elementNode);
    }
    elementNode.childNodes.forEach(function(node) {
      if (node.classList === undefined) {
        return;
      } else if (node.classList.contains(className)) {
        classNameArray.push(node);
      } else {
        return traverseTheNode(node);
      }
    });
  }
};

console.log(getElementsByClassName('targetClassName'))

代码按照我的意愿执行,但是当我 console.log 时,它会抛出错误。 “无法读取 属性 of classList of null”谈论第一个 if 语句。有什么想法吗?

我发现了一个不同的问题。您的数组并未返回 class 的所有实例,仅返回一个。我重新组织了您的 if 语句,以便它会在其他条件之前遍历一个节点的子节点,现在它似乎正在返回所有匹配的节点。

var getElementsByClassName = function(className) {
  var classNameArray = [];
  var bodyElement = document.body;
  var traverseTheNode = function(elementNode) {
    if (elementNode.classList.contains(className)) {
      classNameArray.push(elementNode);
    }
    elementNode.childNodes.forEach(function(node) {
      if (node.hasChildNodes()) {
        return traverseTheNode(node);
      } else if (node.classList === undefined) {
        return;
      } else if (node.classList.contains(className)) {
        classNameArray.push(node);
      }


    });
  }
  traverseTheNode(bodyElement);
  //console.log(classNameArray)
  return classNameArray;
};

console.log(getElementsByClassName('three'))
<div class='three'>
  <ul class="two">
    <li>Hmmm
      <dd class='three'>
      </dd>
    </li>
  </ul>
</div>

这将以上内容转换为更实用的样式:

const gebcn = (className) => (element) => 
  (Array .from (element .classList || []) .includes (className)
    ? [element] 
    : []
  ).concat (
    element .hasChildNodes() 
      ? Array .from (element .childNodes) .flatMap (gebcn (className))
      : []
  )
  
const getElementsByClassName = (className) => gebcn (className) (document .body)

console.log (getElementsByClassName ('three'))
<div class='three'>
  <ul class="two">
    <li>Hmmm
      <dd class='three'>
      </dd>
    </li>
  </ul>
</div>

我们编写了一个更通用的版本,gebcn,它在特定元素 中找到具有给定 class 名称 的所有元素。然后我们在上面写 getElementsByClassName ,默认目标元素为 document.body.

我们的 main 函数简单地测试当前元素以查看它是否具有正确的 class,如果是则将其放入单元素数组中,否则生成一个空数组,然后在任何 childNodes, flatMap将它们合并到一个数组中。