рекурсия не работает без объявления глобальной переменной
почему версия A работает, а версия B-нет? Как я могу заставить версию B работать без объявления глобальной переменной вне функции (что является плохой практикой)? Я не понимаю, почему я не могу просто объявить count внутри самой функции.
A)
var count = 0;
var containsFiveOrMoreDivs = function(domElement) {
if (domElement && domElement.tagName === "DIV") {
count++;
}
//base case:
if (count >= 5) {
return true;
} else {
if (domElement.hasChildNodes()) {
var children = domElement.childNodes;
for (var i = 0; i < children.length; i++) {
if (containsFiveOrMoreDivs(children[i])) {
return true;
}
}
}
return false;
}
};
B)
var containsFiveOrMoreDivs = function(domElement) {
var count = 0;
if (domElement && domElement.tagName === "DIV") {
count++;
}
//base case:
if (count >= 5) {
return true;
} else {
if (domElement.hasChildNodes()) {
var children = domElement.childNodes;
for (var i = 0; i < children.length; i++) {
if (containsFiveOrMoreDivs(children[i])) {
return true;
}
}
}
return false;
}
};
5 ответов
что вам действительно нужно два функции, одна внутри другой:
function containsFiveOrMoreDivs(domElement) {
var count = 0;
function doCount(domElement) {
if (domElement && domElement.tagName === "DIV") {
count++;
}
//base case:
if (count >= 5) {
return true;
}
else {
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);
}
В что настройки, вы передаете ссылку на элемент, а затем внешняя функция вызывает внутреннюю функцию после инициализации счетчика.
оригинал не очень хороший ответ здесь
ваша вторая версия ("B") имеет" count " как локальная переменная функции. Каждый вызов функции получает свой собственный " count" переменная, и в каждом вызове первое, что происходит, - это инициализация до нуля.
Если вы не хотите, глобальный, вы можете использовать замыкание:
var containsFiveOrMoreDivs = function() {
var count = 0;
return function(domElement) {
if (domElement && domElement.tagName === "DIV") {
count++;
}
//base case:
if (count >= 5) {
return true;
} else {
if (domElement.hasChildNodes()) {
var children = domElement.childNodes;
for (var i = 0; i < children.length; i++) {
if (containsFiveOrMoreDivs(children[i])) {
return true;
}
}
}
return false;
}
};
}();
этот код обертывает вашу фактическую функцию счетчика в анонимную функцию, которая включает переменную "count". Он не будет глобальным; он будет полностью приватным для функции "containsFiveOrMoreDivs". Это похоже на лучшее из обоих миров: вы можете рассматривать "count" как глобальный, но это не глобальный. Вам не нужно беспокоиться о проведении параметра вокруг.
переменные в Javascript существуют в области функций. Каждый раз, когда вы вызываете containsFiveOrMoreDivs, count всегда будет 0 в вашей версии B. следовательно, бесконечная рекурсия.
что вы можете сделать, однако, это передать "count" каждый раз, когда вы вызываете из функции, и использовать это (гарантируя, что он правильно инициализирован в первый раз):
var containsFiveOrMoreDivs = function(domElement, count) {
if (!count) {
count=0;
}
if (domElement && domElement.tagName === "DIV") {
count++;
}
//base case:
if (count >= 5) {
return true;
} else {
if (domElement.hasChildNodes()) {
var children = domElement.childNodes;
for (var i = 0; i < children.length; i++) {
if (containsFiveOrMoreDivs(children[i], count)) {
return true;
}
}
}
return false;
}
};
назовите это так же, как вы в настоящее время (containsFiveOrMoreDivs('elementname');
)
версия B не будет работать, потому что каждый раз, когда функция называется counter
объявлено заново, так что counter
никогда не увеличивается.
ваша рекурсивная функция должна использовать count в качестве аргумента. Кстати у вас это будет инициализировать счетчик до 0 не важно, сколько раз вам повторить.
вот пример рекурсивной функции, которая потребляет" количество раз, чтобы что-то сделать " в качестве параметра. Изменить его, чтобы поддержать ваше дело. Ваш базовый случай будет чем-то вроде "count больше 5", и каждый раз, когда вы вызываете рекурсивно, вы добавляете 1 к счету, который вы предоставляете рекурсивному вызову.
function executeMany(fn, count) {
if (count > 0) {
fn();
executeMany(fn, count - 1)
}
}
// this logs "Test" to the console twice
executeMany(function() { console.log("Test"); }, 2);
вы можете определить функцию с count
параметр и передайте начальное значение или если вы используете ECMA 16, вы можете установить значение по умолчанию для параметра, выполнив count=0
.
var containsFiveOrMoreDivs = function(domElement, count) {
if (domElement && domElement.tagName === "DIV") {
count++;
}
//base case:
if (count >= 5) {
return true;
} else {
if (domElement.hasChildNodes()) {
var children = domElement.childNodes;
for (var i = 0; i < children.length; i++) {
if (containsFiveOrMoreDivs(children[i]), count) {
return true;
}
}
}
return false;
}
};
// call function and set counter to some initial value, such as zero
containsFiveOrMoreDivs(domElement, 0);