Рекурсия в 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: