Nesse artigo, trataremos do assunto de referência cíclica, ou dependências circulares, um comportamento que, embora não gere erros, pode certamente resultar em grandes problemas em produção.
Primeiramente, o que é uma referência cíclica?
Trata-se de uma série de referências onde um objeto refere-se a si mesmo (direta ou indiretamente) por meio de uma série de outros objetos, originando um ciclo fechado.
Podem acontecer de maneira direta ou indireta, dentro de closures ou de classes.
Direta
let usuario = {
primeiroNome: 'Maria'
};
usuario.self = usuario;
console.log(usuario); //imprime <ref *1> { primeiroNome: 'Maria', self: [Circular *1] }
console.log(usuario.self); //imprime <ref *1> { primeiroNome: 'Maria', self: [Circular *1] }
console.log(usuario.self.self); //imprime <ref *1> { primeiroNome: 'Maria', self: [Circular *1] }
// Mesma saída, visto que é apenas uma referência para o próprio objeto
Ou, ainda, dessa maneira:
let x = {}; //objeto x é um objeto vazio
x.x = x; //usando notação ponto, atribuindo à propriedade x do objeto x o valor dele mesmo
console.log(x); //imprimindo, o valor é <ref *1> { x: [Circular *1] }
Indireta
De forma indireta, seria:
//um objeto criado primeiro...
let usuario = {
primeiroNome: 'Maria'
};
let perfil = {
usuario: usuario, //... que é referenciado depois dentro de outro objeto...
perfil_id: 123456
};
//...e a referência ao último objeto
console.log(perfil); //imprime { usuario: { primeiroNome: 'Maria' }, perfil_id: 123456 }
Classes
Em classes, seria algo como:
class Usuario {
constructor(nome) { //dessa vez, usando um construtor
this.nome = nome;
this.self = this; //novamente, aqui a referência cíclica
}
}
let usuario = new Usuario('Bruce');
console.log(usuario.self.self.self.self.name); //imprime Bruce
Closures
E, finalmente, em closures:
let foo;
foo = function(arg) {
if (arg) console.log(arg); //se houver um argumento, imprime esse argumento...
else foo('Favor informar o nome!'); //...caso contrário, imprime a mensagem
}
foo('Claúdio'); //imprime Cláudio
foo(); //imprime 'Favor informar o nome!' visto que nenhum nome foi passado
A função dentro da variável foo se refere a ela mesma, criando a referência cíclica.
É um comportamento desejável?
Não! Por mais que as referências cíclicas não ofereçam algum erro de fato, não são um comportamento que se busca dentro de um código, visto que podem gerar consequências não intencionais que causam um efeito “bola de neve” bem chato de se corrigir, então o melhor mesmo a fazer é evitar.
Conclusão
Espero que tenham curtido este pequeno artigo sobre referências cíclicas em JavaScript, um assunto tão pouco abordado, mas com comportamentos deveras interessantes!
Bons estudos!