重构用于遍历 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 布尔值。
@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 布尔值。