重构用于遍历 DOM 的工作递归代码 (hasFiveDIVs)

refactoring working recursion code (hasFiveDIVs) for traversing the DOM

@oriol 为我今天处理的问题提供了一个惊人的两行递归解决方案。

function numOccurencesRecursive(arr, val) {
  if (!arr.length) return 0;
  return (arr[0] === val ? 1 : 0) + numOccurencesRecursive(arr.slice(1), val);
}

我受到启发重构了我昨天写的一些意大利面条式的代码:

//returns a boolean
    function containsFiveOrMoreDivs(domElement) {
      var count = 0;

  function doCount(domElement) {
    if (domElement && domElement.tagName === "DIV") {
      count++;
    }

    if (count >= 5) {
      return true;
    }

    if (domElement.hasChildNodes()) {
      var children = domElement.childNodes;
      for (var i = 0; i < children.length; i++) {
        if (doCount(children[i])) {
          return true
        }
      };
    };

    return false;
  }

  return doCount(domElement)
}
containsFiveOrMoreDivs(document);

这是尝试:

function containsFiveOrMoreDivsPureRecursion(domElement) {
  if (!domElement && domElement.tagName !== "DIV") {
    return 0;
  }
  return (domElement.tagName === "DIV" ? 1 : 0) + containsFiveOrMoreDivsPureRecursion(domElement.childNodes()); //?
}

在这个版本中,我将如何递归地遍历所有子节点?我正在做的事情可行吗?

使用递归,您应该记住 return 1 种类型的值,但是您想要 return 一个布尔值,但您希望您的函数也 return 计数。这确实使事情复杂化。

这里是一个递归函数,用来统计元素类型

function countElements(domElement, elementType) {
    count = (domElement && domElement.tagName === elementType.toUpperCase());

    if (domElement.hasChildNodes()) {
      for (var i = 0; i < domElement.childNodes.length; i++) {
        count += countElements(domElement.childNodes[i], elementType); 
      };
    };

    return count;
}

你可以像这样使用它来实现你想要的。

countElements(document, 'div') >= 5

但是,这可能不是最有效的方法,因为它会遍历整个 DOM 树,但您真正想要的是它在达到 5 个元素时停止。

function containsFiveOrMoreDivsPureRecursion(domElement, elementType) {
    var count = 0;

    function countElements(domElement, elementType) {
        count += (domElement && domElement.tagName === elementType.toUpperCase());

        if (count >= 5) return count;

        if (domElement.hasChildNodes()) {
          for (var i = 0; i < domElement.childNodes.length; i++) {
            countElements(domElement.childNodes[i], elementType); 
          };
        };

        return count;
    }


    return countElements(domElement, elementType) >= 5;
}

在此示例中,您需要在函数外部保留一个变量(因此它不是真正的纯递归)以跟踪计数并能够 return 布尔值。