Recursão com vanilla JavaScript
Tags: javascript, programming, portugues
Published: 2023-12-09 20:33:33

_**Nota:** apenas traduzi o texto abaixo e postei aqui._

Em JavaScript, recursão ocorre quando você chama uma function de dentro dela até ou a menos que uma condição seja atendida. Hoje, vamos ver como funciona.

## Um exemplo

Digamos que você tenha uma coleção de elementos aninhados, como este:

```html
<div class="bg-1">
    <div class="bg-2">
        <div class="bg-3">
            <div class="bg-4">
                <div class="bg-5">
                    <div class="bg-6">
                        <div class="bg-7">
                            ...
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
```

Você deseja escrever uma JavaScript function que permita obter a distância na `DOM tree` entre um `element` e seu `parent`. Por exemplo, `.bg-5` está dois níveis acima de `.bg-7`.

## Criando uma helper function

Primeiro, vamos criar uma `levelsUp() helper function`.

Passaremos um `element` e um `selector` como arguments. Também adicionaremos um terceiro argument que usaremos para rastrear a distância entre nosso element e um element com o selector.

```javascript
var levelsUp = function (elem, selector, distance) {
    // Faça as coisas...
};
```

Não queremos que os usuários tenham que definir a distância como `0` toda vez que executarem a function.

Verificaremos se um valor para `distance` existe e, caso contrário, definiremos como `0`. Em seguida, usaremos `++` para aumentar nosso valor de `distance` em `1`.

```javascript
var levelsUp = function (elem, selector, distance) {
    // Se distance não é definido ainda, configura ele para 0
    if (!distance) {
        distance = 0;
    }

    // Aumenta a distance em 1
    distance++;
};
```

A seguir, obteremos o parent do element atual com a propriedade `elem.parentNode`.

```javascript
var levelsUp = function (elem, selector, distance) {
    // Se distance não é definido ainda, configura ele para 0
    if (!distance) {
        distance = 0;
    }

    // Aumenta a distance em 1
    distance++;

    // Obtêm o parent do element atual
    var parent = elem.parentNode;
};
```

Agora, podemos usar o método `matches()` para verificar se o parent corresponde ao selector.

Se o parent for compatível, podemos retornar nossa `distance`.

```javascript
var levelsUp = function (elem, selector, distance) {
    // Se distance não é definido ainda, configura ele para 0
    if (!distance) {
        distance = 0;
    }

    // Aumenta a distance em 1
    distance++;

    // Obtêm o parent do element atual
    var parent = elem.parentNode;

    // Se alcançamos o parent, retorne a distance
    if (parent.matches(selector)) return distance;
};
```

## Adicionando recursão

Agora, é aqui que entra a recursão.

Se o parent não corresponder, queremos executar `levelUp()` novamente, usando o parent como nosso element inicial. Também passaremos o `selector` e nossa `distance` atual.

E como a function precisa retornar um valor, retornaremos qualquer que seja o output de nossa function recursiva `levelUp()`.

```javascript
var levelsUp = function (elem, selector, distance) {
    // Se distance não é definido ainda, configura ele para 0
    if (!distance) {
        distance = 0;
    }

    // Aumenta a distance em 1
    distance++;

    // Obtêm o parent do element atual
    var parent = elem.parentNode;

    // Se alcançamos o parent, retorne a distance
    if (parent.matches(selector)) return distance;

    // Caso contrário, execute recursivamente levelUp() novamente
    return levelsUp(parent, selector, distance);
};
```

O método `levelsUp()` será executado várias vezes até encontrar uma correspondência ou atingir o window element e retornará qualquer que seja o valor final da `distance` (ou `-1` se nenhuma correspondência for encontrada).

E com isso, agora temos uma function recursiva.

## Um último detalhe

Se não houver nenhum selector correspondente, você pode acabar subindo o suficiente na `DOM tree` e atingir um element que não suporta o método `matches()` (como o `window`).

Antes de tentar usar `matches()`, vamos primeiro verificar se o parent suporta esse método. Caso contrário, retornaremos `-1` e assumiremos que não há correspondência.

```javascript
var levelsUp = function (elem, selector, distance) {
    // Se distance não é definido ainda, configura ele para 0
    if (!distance) {
        distance = 0;
    }

    // Aumenta a distance em 1
    distance++;

    // Obtêm o parent do element atual
    var parent = elem.parentNode;

    // Se você chegar a um elemento sem método matches(), desiste
    if (!parent.matches) return -1;

    // Se alcançamos o parent, retorne a distance
    if (parent.matches(selector)) return distance;

    // Caso contrário, execute recursivamente levelUp() novamente
    return levelsUp(parent, selector, distance);
};
```

## Fonte

Newsletter de [Go Make Things](https://gomakethings.com/)