Рекурсия в JavaScript
В JavaScript рекурсия - это когда вы вызываете функцию изнутри себя до тех пор, пока условие не будет выполнено. Сегодня давайте посмотрим, как это работает.
Пример
Допустим, у вас есть коллекция вложенных элементов, например:
...
Вы хотите написать функцию JavaScript, которая позволит вам получить расстояние в дереве DOM между элементом и его родителем. Например, .bg-5 на два уровня выше .bg-7.
Создание вспомогательной функции
Сначала давайте создадим функцию levelsUp().
Мы передадим в elem и selector в качестве аргументов. Мы также добавим третий аргумент, который будем использовать для отслеживания distance между нашим elem и selector.
var levelsUp = function (elem, selector, distance) {
// Do stuff...
};
Мы хотим, чтобы пользователи могли не передавать distance каждый раз, когда они работают с функцией.
Мы проверим, существует ли значение distance, и если нет, мы установим ему значение 0. Затем мы будем использовать ++ для увеличения нашего значения distance на 1.
var levelsUp = function (elem, selector, distance) {
// If distance isn't defined yet, set it to 0
if (!distance) {
distance = 0;
}
// Increase the distance by 1
distance++;
};
Далее мы получим parent от текущего elem с помощью свойства elem.parentNode.
var levelsUp = function (elem, selector, distance) {
// If distance isn't defined yet, set it to 0
if (!distance) {
distance = 0;
}
// Increase the distance by 1
distance++;
// Get the parent of the current element
var parent = elem.parentNode;
};
Теперь мы можем использовать метод matches(), чтобы проверить, совпадает ли parent c selector.
Если parent совпадение, мы можем вернуть наш distance.
var levelsUp = function (elem, selector, distance) {
// If distance isn't defined yet, set it to 0
if (!distance) {
distance = 0;
}
// Increase the distance by 1
distance++;
// Get the parent of the current element
var parent = elem.parentNode;
// If we've reached the parent, return the distance
if (parent.matches(selector)) return distance;
};
Добавление рекурсии
Вот здесь и начинается рекурсия.
Если parent не совпадает, мы хотим запустить снова levelsUp(), используя parent в качестве нашего начального элемента. Мы также передадим selector, и наш distance.
И поскольку функция в конечном итоге должна возвращать значение, мы с помощью return получим любой результат нашей рекурсивной функции levelsUp().
var levelsUp = function (elem, selector, distance) {
// If distance isn't defined yet, set it to 0
if (!distance) {
distance = 0;
}
// Increase the distance by 1
distance++;
// Get the parent of the current element
var parent = elem.parentNode;
// If we've reached the parent, return the distance
if (parent.matches(selector)) return distance;
// Otherwise, recursively run levelsUp() again
return levelsUp(parent, selector, distance);
};
Метод levelsUp() будет выполняться несколько раз до тех пор, пока не найдет совпадение или попадет в элемент window, и будет возвращать конечное значение distance если совпадение найдено (или , -1 если не найдено).
И теперь у нас есть рекурсивная функция.
Одна последняя деталь
Если соответствия selector нет, вы можете оказаться достаточно далеко в дереве DOM, чтобы попасть в элемент, который не поддерживает метод matches() (например, в window).
Прежде чем пытаться использовать matches(), давайте сначала проверим, поддерживает ли parent этот метод. Если нет, мы вернемся -1 и предположим, что совпадения нет.
var levelsUp = function (elem, selector, distance) {
// If distance isn't defined yet, set it to 0
if (!distance) {
distance = 0;
}
// Increase the distance by 1
distance++;
// Get the parent of the current element
var parent = elem.parentNode;
// If you we reach an element with no matches() method, bail
if (!parent.matches) return -1;
// If we've reached the parent, return the distance
if (parent.matches(selector)) return distance;
// Otherwise, recursively run levelsUp() again
return levelsUp(parent, selector, distance);
};
Поиграться на CodePen: