360 pessoas já começaram a estudar hoje
360360pessoasjá começaram a estudar hoje
já começaram a estudar hoje

Enquanto você avalia,

360360pessoas já começaram a estudar hoje

Dê o próximo passo e inicie sua carreira

Dê o próximo passo e inicie sua carreira agora mesmo

Comece agora
  • Home

    Escolha seu Plano

    • Plus 2430% OFF
    • Pro 2430% OFF
    • Ultra Lab 2430% OFF

    Carreiras Alura

    Evolua com profundidade técnica, direção clara e aplicação prática.

    Jornadas guiadas do básico ao avançado com checkpoints práticos, desenhadas para quem busca profundidade e protagonismo técnico.

    Iniciante

    Comece do zero com uma trilha clara e progressiva.

    Fundamentos práticos para dar os primeiros passos com segurança e construir uma base sólida.

    Intermediário

    Continue sua evolução com cursos que conectam fundamentos, ferramentas e prática profissional. Ganhe autonomia, e avance para projetos mais completos.

    Avançado

    Aprofunde temas técnicos e estratégicos para enfrentar desafios mais complexos. Explore boas práticas, arquitetura, performance com visão profissional.

    Cursos

    Ver mais cursos de Back-end
    • Pensamento computacional: fundamentos da computação e lógica de programação
    • Lógica de programação: mergulhe em programação com JavaScript
    • DDD: fundamentos do design orientado a domínio
    • ASP.NET: autenticação e autorização em APIs e aplicações web
    • Microsserviços: migração de monólitos e modularização

    Cursos

    Ver mais cursos de Dados
    • Python para Dados: primeiros passos
    • Excel: domine o editor de planilhas
    • Engenharia de Dados: Orquestração de Pipelines com Apache Airflow
    • Power BI Desktop: construindo meu primeiro dashboard
    • Governança e Arquitetura de Dados

    Cursos

    Ver mais cursos de Inteligência Artificial
    • IA: Explorando o Potencial da Inteligência Artificial Generativa
    • Engenharia de Prompt: Criando Prompts Eficazes para IA Generativa
    • Claude para Análise de Dados: prompts, integrações e automações
    • Agno: criando agentes e sistemas multiagente
    • Engenharia de software na era da IA: segurança de aplicações com agentes, MCPs e código gerado por IA

    Cursos

    Ver mais cursos de Front-end
    • HTML e CSS: ambiente, estrutura e estilo
    • React: realizando testes avançados com Jest e Testing Library
    • React: integrando TypeScript em projetos
    • JavaScript: aprendendo a programar
    • React: aplicando arquiteturas de Micro frontends

    Cursos

    Ver mais cursos de DevOps
    • Sistema Operacional Linux: fundamentos e administração prática
    • Containers e Docker: empacotamento, isolamento e gestão
    • Redes: dos conceitos iniciais à criação de uma intranet
    • Linux: gerenciando diretórios, arquivos, permissões e processos
    • Cibersegurança: Fundamentos e práticas integradas

    Cursos

    Ver mais cursos de UX & Design
    • UX Research: mapeando a experiência da pessoa usuária
    • UX/UI Design: Entregando produtos digitais com IA
    • UI Design: Prototipação e animações interativas
    • Figma: Conhecendo o programa
    • Product Design: métricas e ciclo de vida do produto

    Cursos

    Ver mais cursos de Inovação e Gestão
    • Canva: Criação de landing pages e e-mail marketing
    • Agilidade: como ela pode ajudar a criar um time de alta performance
    • Google Analytics 4: Extrair insights e configurar eventos
    • Management 3.0: gerencie o ambiente, não as pessoas
    • Automação de processos com n8n: Inteligência de dados para Marketing

    Cursos

    Ver mais cursos de Mobile
    • React Native: Estilização e Layouts com Flexbox e StyleSheet
    • Flutter: Graphql e suporte offline
    • Android com Gemini: Trabalhando com textos e imagens na IA
    • Dart: trabalhando com orientação a objetos
    • React Native: Dominando Listas com FlatList e ScrollView

    Carreiras

    Ver mais carreiras
    • Especialista em IA
    • Engenharia de IA
    • Ai native software engineering
    • Arquitetura de Soluções com IA
    • AI Product Design
    • Engenharia de Machine Learning
    • Desenvolvimento Front-End React
    • Engenharia de Dados
    • Cloud Security
    • Social Media Marketing
    • Engenharia de Agentes de IA

    Cursos

    • Engenharia de Prompt: Prompts Eficazes para IA Generativa
    • Claude Code: Criando sua Primeira Aplicação
    • Python: Crie sua Primeira Aplicação
    • Git e GitHub: Compartilhando e Colaborando
    • N8N: Fluxos de Trabalho Avançados

    Cursos

    • Copilot Studio: Solução Multiagentes
    • Padrões de API HTTP e Modelagem de APIs
    • Python para Análise de Dados com SQL
    • Docker: Criando e Gerenciando Containers
    • Design com IA: Otimizando o Processo Criativo

    Cursos

    • Model Context Protocol (MCP)
    • Spec-Driven Development: Dev Assistido por Agentes
    • Arquitetura de Sistemas Distribuídos com Java
    • Governança de Modelos e Reprodutibilidade
    • Pentest: Vulnerabilidades em Aplicações Web

    Escolha seu Plano

    • Plus 2430% OFF
    • Pro 2430% OFF
    • Ultra Lab 2430% OFF

    Skills & Go

    O Skills & Go é para Tech Leads, Product Managers, estrategistas e early adopters que transformam ideias em soluções de alto impacto. Em cursos ao vivo e 100% online, você domina a nova era da IA em tempo real.

    Aulas ao vivo

    Saiba mais
    • Agentic Engineering: orquestre múltiplos agentes com confiabilidade
    • Building AI Products: transforme ideias em produtos reais com IA
    • AI Data Strategy: transforme dados em decisões estratégicas com IA

    Escolha seu Plano

    • Plus 2430% OFF
    • Pro 2430% OFF
    • Ultra Lab 2430% OFF

    Eventos Alura

    Nossos eventos são pensados para quem quer estar à frente das mudanças em tecnologia, IA e inovação. Em experiências presenciais, você acompanha tendências e se conecta com especialistas que estão moldando o futuro.

    Próximos eventos

    • IA Conference
    • Alura Signals
  • Talent Lab
  • IA

    Escolha seu Plano

    • Plus 2430% OFF
    • Pro 2430% OFF
    • Ultra Lab 2430% OFF

    Conteúdos gratuitos

    Explore conteúdos gratuitos para aprender tecnologia no seu ritmo. Encontre artigos com conteúdos técnicos para aprender na prática, notícias para acompanhar as principais tendências do mercado e o Alura Labs, com análises e reflexões de especialistas sobre tecnologia, IA e carreira.

    Conteúdos gratuitos

    • Artigos
    • Notícias
    • Alura Labs
  • Para Empresas
Ver planos
Links principais
  • Planos e Promoções
  • Carreiras

    Ver todas
    • Especialista em IA
    • Engenharia de IA
    • Ai native software engineering
    • Arquitetura de Soluções com IA
    • AI Product Design
    • Engenharia de Machine Learning
    • Desenvolvimento Front-End React
    • Engenharia de Dados
    • Cloud Security
    • Social Media Marketing
    • Engenharia de Agentes de IA
    Entrar Ver Planos
  • Área de Interesse

    Entrar Ver Planos
  • Aulas ao Vivo - Skills & Go

    • Agentic Engineering: orquestre múltiplos agentes com confiabilidade
    • Building AI Products: transforme ideias em produtos reais com IA
    • AI Data Strategy: transforme dados em decisões estratégicas com IA
    Entrar Ver Planos
  • Senioridade

    Entrar Ver Planos
  • Eventos Alura

    • IA Conference
    • Alura Signals
    Entrar Ver Planos
  • Conteúdos

    • Artigos
    • Notícias
    • Alura Labs
    Entrar Ver Planos
  • Links complementares do menu mobile
  • Talent lab
  • Inteligência Artificial
  • Pós Graduações
  • Para Empresas
  • Sobre a Alura
  • Grupo Alun
  • Entrar
    • Home
    • Carreiras
    • Skills & Go
    • Talent Lab
    • Inteligência Artificial
    • Pós Graduações
    • Artigos
    • Sobre a Alura
    • Grupo Alun
    LoginContato
    • Plano Pro 24
    • Plano Plus 24
    • Plano Ultra Lab 24
    • LinkedIn
    • Instagram
    • YouTube
    1. Página inicial
    2. Back-end
    3. Vamos implementar uma função de clonagem profunda com imutabilidade em JS?

    Vamos implementar uma função de clonagem profunda com imutabilidade em JS?

    14 min14 minutos de leitura

    14 min14 minutos de leitura

    Publicado: 13/09/2022

    1. Introdução
    2. Como os tipos de dados do Javascript são armazenados em memória

    Introdução

    Este artigo foi escrito pelo aluno Caique Moraes.

    Há um tempo, estive entusiasmado estudando sobre o paradigma funcional, fortemente utilizado em frameworks como React. Um de seus princípios, a imutabilidade, prega que nenhum dado/estado deve ser alterado, e sim evoluído e transformado. Este princípio garante a consistência de uma informação, que pode ser acessada e lida por diversos pontos de um software, mas que nenhum destes pontos podem alterá-la, causando uma violação. Somente um único ponto isolado pode evoluir essa informação e disponibilizá-la para o restante do software consumir.

    Isso despertou, em mim, uma imensa curiosidade sobre como construir uma informação imutável, e mesmo se fosse replicada, seus clones não poderiam causar impacto na informação original, pois estes clones, internamente, correspondem a novos endereços de memória.

    Existem bibliotecas como lodash, que possuem funções capazes de criar clones em profundidades de estruturas complexas mas, para mim, não bastava adicionar em meus projetos uma biblioteca que fizesse isso. O que eu queria era ver o que de fato acontecia debaixo dos panos dentro de uma função capaz de clonar grandes estruturas de dados. O grande físico Richard Feynman dizia: "Aquilo que eu não posso criar, não consigo entender".

    Essa busca me levou há alguns conceitos-chave que nos levarão a um novo patamar como programadores. Tais conceitos serão apresentados ao longo deste artigo: como o Javascript armazena dados em memória, e como construir uma função capaz de identificar o tipo de um dado; e por fim construiremos uma função utilizando Javascript puro, capaz de produzir clones imutáveis.

    Vamos aos primeiros conceitos-chave?!

    Pra começar: existem diversas maneiras de se clonar uma estrutura de dados como arrays e objetos. Entretanto, há dois tipos de clonagens:

    1. Uma clonagem superficial, também chamada de Shallow Clone, que copia somente a superfície de uma estrutura alvo para um outro endereço de memória, e mantém suas propriedades apontando para o mesmo endereço de memória da estrutura original. Qualquer alteração nas propriedades internas de um Shallow Clone afetará a estrutura original e vice-versa.
    2. Temos também a clonagem profunda chamada Deep Clone, que realiza uma cópia da estrutura alvo e todas as suas propriedades internas para novos endereços de memória. Isto é, o Deep Clone gera uma nova estrutura idêntica e desconectada da estrutura original, em que qualquer alteração nesta estrutura não refletirá na estrutura original.

    Cada uma destas técnicas de clonagem “brilha” em contextos diferentes. Quando trabalhamos com estruturas constituídas de tipos primitivos, não há necessidade de criarmos mecanismos complexos e custosos para clonagem, podemos seguir com a técnica de Shallow Clone. Porém, ao trabalharmos com estruturas de dados complexas e aninhadas, o Deep Clone é a melhor alternativa.

    Ao longo deste artigo serão apresentadas as motivações para utilizar a técnica de Deep Clone, e como bônus vamos implementar uma técnica de imutabilidade para garantirmos que nossos dados não poderão ser alterados. Então, bora lá!

    Banner promocional da Alura destacando até 30% de desconto e mais 1 mês grátis para quem quer investir na carreira e acelerar sua evolução profissional. A oferta é por tempo limitado, com matrícula disponível até 24 de agosto e chamada para aproveitar a oportunidade de estudar na Alura.

    Como os tipos de dados do Javascript são armazenados em memória

    Sabemos que o Javascript possui dois grupos de tipos de dados: os tipos primitivos e os tipos não primitivos, compostos por: Boolean, Null, Undefined, BigInt, String, Number e Symbol.

    Os tipos primitivos são imutáveis por natureza. Ao realizar qualquer alteração em um tipo primitivo, o próprio interpretador do Javascript, em tempo de execução, se encarregará de alocar um novo endereço de memória para o resultado transformado:

    let num1 = 0
    let num2 = num1
    num2++
    

    console.log(num1) // 0 console.log(num2) // 1

    Quando a variável num1 foi criada, o interpretador do Javascript criou um identificador único para ela. Alocou um endereço na memória (por exemplo, EJ0001), e armazenou o valor "1" no endereço alocado.

    Representação da variável num1 apontando para o endereço de memória EJ0001.

    Quando definimos que num2 é igual a num1, o que o Javascript fez por debaixo dos panos foi:

    1. Definiu um identificador único para a variável: num2.
    2. Apontou o identificador para o mesmo endereço de memória da variável num1 (ex: EJ0001).

    Representação das variáveis num1 e num2 apontando para o endereço de memória EJ0001.

    Mas na linha 3, no momento em que incrementamos o valor da variável num2, o Javascript alocou uma nova unidade de memória (por exemplo: XJ0501) , armazenou o valor da expressão: "num2++" e apontou o identificador da variável num2 para este novo endereço de memória. Portanto, teremos duas variáveis apontando para dois endereços de memória distintos.

    Representação das variáveis num1 e num2 apontando cada uma para um endereço de memória distinto.

    Este comportamento é diferente se for realizado com objetos e arrays, que são considerados tipos não primitivos. Estas estruturas de dados são armazenadas em outra região dentro da arquitetura da linguagem. Esta região chama-se Heap, e ela é capaz de armazenar dados não ordenados que podem crescer e diminuir dinamicamente como objetos e arrays.

    Quando declaramos uma variável "person", e atribuímos a ela um tipo não primitivo como um objeto vazio:

    const person = {}
    

    É isso que acontece por debaixo dos panos:

    1. Um identificador é criado com o nome "person".
    2. Um endereço de memória é alocado em tempo de execução na Stack (ex: CM9323).
    3. É armazenado neste endereço criado na Stack, uma referência para um endereço de memória alocado na Heap.
    4. O endereço de memória na Heap armazenará o valor que foi atribuído a "person", neste caso um objeto vazio.

    A partir deste ponto, qualquer alteração que fizermos no objeto person acontecerá na Heap, e todas as variáveis que apontam para o mesmo endereço de memória de person, serão afetadas pela mudança.

    const person = {}
    const clonedPerson = person
    person.name = 'John'
    

    console.log(person.name) // 'John' console.log(person.clonedPerson) // 'John'

    Este é o comportamento nativo do Javascript na hora de lidar com a memória. Mas por que ele se comporta desse jeito? Justamente para economizar memória e ganharmos performance.

    Imagine um cenário hipotético onde temos um simples array com 1 milhão de itens. Se copiarmos este array 10 vezes, teremos 10 arrays distintamente desconectados com 1 milhão de itens cada, totalizando em 10 milhões de itens. Sendo que 9 milhões destes, são cópias idênticas do primeiro array.

    Mas, em certos casos, principalmente quando trabalhamos seguindo o princípio da imutabilidade, um dos pilares do paradigma funcional, queremos ter um comportamento diferente. Gostaríamos de copiar todos os valores que estão contidos dentro de endereços de memória, para novos endereços de memória. Esta prática nos livra do efeito colateral presente na concorrência de acesso a dados: Se dois locais distintos da aplicação concorrem para acessarem e subscreverem um mesmo recurso, no mesmo instante de tempo, um dos locais que espera receber uma "bola", pode obter um "quadrado" devido a atualização que o outro local fez anteriormente.

    Construindo uma função de checagem de tipos

    Para iniciarmos nosso exemplo, desenvolveremos uma função capaz de checar o tipo de qualquer variável que passamos para ela e nos retornar seu tipo em formato de string em caixa baixa.

    Essa função nos auxiliará a testar o tipo de nossas estruturas arrays e objetos, além de enriquecer seu repertório de programador:

    const typeCheck = (type) => {
      const typeString = Reflect.apply(Object.prototype.toString, type, [])
      return typeString.slice(
        typeString.indexOf(' ') + 1,
        typeString.indexOf(']')
      ).toLowerCase()
    }
    

    Basicamente nossa função typeCheck recebe um valor, em cima deste valor executamos a chamada do método toString, presente no prototype dos objetos com auxílio da API Reflect, que nos assegura a devida execução de toString. O seu retorno será uma string envolvida por colchetes como a seguinte representação: [object String]. Por fim, com auxílio das funções slice, indexOf e toLowerCase presentes nas strings, podemos manipular nosso resultado e devolver uma string que representa o valor passado como parâmetro em nossa função.

    Normalmente alguém me perguntaria:

    • Por que você não usa o operador typeof do próprio Javascript ao invés de criar uma função como essa?

    O typeof não sabe diferenciar um null de um object.

    console.log(typeof null === typeof {}) // true
    

    O resultado de nossa função para diferentes tipos:

    console.log(typeCheck([])) // array
    console.log(typeCheck(null)) // null
    console.log(typeCheck({})) // object
    console.log(typeCheck('teste')) // string
    console.log(typeCheck(123)) // number    
    

    Construindo uma função de clonagem profunda de arrays

    Para construirmos uma função que clona profundamente uma estrutura de array, precisamos adentrar em cada posição e testá-la. Se cada posição do array for um array, adentre neste e teste-o. E assim recursivamente até chegar na condição de parada, em nosso caso, qualquer valor diferente de um array.

    const cloneArray = (element) => {
      const clonedArray = []
      for (const item of element) {
        if (typeCheck(item) === 'array') clonedArray.push(cloneArray(item))
        else clonedArray.push(item)
      }
      return clonedArray
    } 
    

    O resultado é uma função bonita, estruturada e imperativa.

    Vamos fazer um ajuste simples, torná-la ainda mais enxuta e declarativa, nos beneficiando da magia da programação funcional:

    const cloneArray = (element) => {
      if (typeCheck(element) !== 'array') return element
      return element.map(cloneArray)
    }
    

    Testando e comparando o resultado de nossa função cloneArray. Observe que abaixo temos 2 exemplos, no primeiro apontamos numbersCopy para o mesmo endereço de memória de numbers. Portanto a saída no console na linha 3 é "true". Mas na linha 4 nossa função entra em ação, clonando o array numbers para outra posição na memória, por isso o resultado é "false".

    const numbers = [1, 2, 3]
    const numbersCopy = numbers
    console.log(numbers === numbersCopy) // true
    console.log(numbers === cloneArray(numbers)) // false
    

    Construindo uma função de clonagem profunda de objetos

    Seguindo o mesmo raciocínio de nossa função cloneArray, vamos construir a cloneObject. O seu objetivo será percorrer as propriedades de um objeto e copiá-las para um novo objeto. Para isso vamos utilizar novamente da técnica de recursividade, pois não temos um limite pré-definido de profundidade, enquanto houver uma propriedade que seja do tipo "object", entre nela e percorra-a também retornando um novo objeto.

    const cloneObject = (element) => {
      if (typeCheck(element) !== 'object') return element
      // implementação
    }
    

    Primeiro passo, dentro de nossa função cloneObject, devemos testar o tipo de dado recebido por argumento, no caso a variável "element". Se o tipo de element for diferente de "object", return element. Senão, prossiga para o restante da implementação.

    A partir desta etapa, na linha 3 precisamos retornar um novo "objeto" que conterá uma cópia das propriedades de "element". Há diversas formas de realizar essa implementação, mas optei pela abordagem declarativa para nos aprofundarmos um pouco mais nas maravilhas do universo do paradigma funcional.

    A função construtora de objetos “Object” possui um método estático chamado fromEntries. Este método retorna um novo objeto a partir de uma estrutura de dados que se assemelha a um array bidimensional: ['chave', 'valor'] ]. Ex.:

    console.log(Object.fromEntries([['nome', 'caique'], ['age', 27]]))
    // { nome: 'caique', age: 27 }
    

    Partindo deste ponto, podemos obter todas as chaves de propriedades de element por meio de um array, com o método "Object.keys" e em cima deste array podemos mapear um novo array bidimensional, onde cada valor de propriedade será passada recursivamente para a função "cloneObject":

    const cloneObject = (element) => {
      if (typeCheck(element) !== 'object') return element
      return Object.fromEntries(
        Object.keys(element).map(key =>
          [key, cloneObject(element[key])]
        )
      )
    }
    

    Na linha 4 obteremos um array contendo todas as chaves das propriedades do objeto "element". Por meio do método "map", vamos percorrer cada posição deste array retornando um novo array onde o valor da respectiva propriedade de "element" que está sendo iterada, será passado para dentro de cloneObject recursivamente. Se este valor não for do tipo "object", retorna-o. Senão, intere por suas propriedades e teste-as.

    Testando nossa função, obteremos o seguinte resultado ao clonar um objeto:

    const user = { name: 'caique', address: {country: 'Brazil', state: 'SP'} }
    const clonedUser = user
    console.log(user.address === clonedUser.address) // true
    console.log(user.address === cloneObject(user).address) // false
    

    Observe que na linha 3 estamos comparando a propriedade address, um objeto aninhado dentro de user, com a propriedade address de clonedUser. Como ambos apontam para o mesmo endereço de memória, o resultado é "true". Na linha 4, colocamos cloneObject em ação e fizemos a mesma comparação, desta vez obtivemos "false", pois o novo objeto gerado com suas propriedades estão apontando para outro endereço de memória.

    Construindo a função deepClone

    Perfeito, agora temos nossas funções de clonagem de array e de objeto. Tudo que precisamos fazer é uni-las em nossa orquestra. Para isso criaremos uma função que será responsável por decidir qual clonagem será executada de acordo com o dado informado:

    const deepClone = (element) => {
      switch (typeCheck(element)) {
        case 'array':
          return cloneArray(element)
        case 'object':
          return cloneObject(element)
        default:
          return element
      }
    }
    

    A deepClone avaliará o element, se ele for do tipo array, execute o cloneArray. Se ele for do tipo object, execute o cloneObject. Caso não entre em nenhuma dessas condições, apenas retorna seu valor original.

    Agora precisamos fazer um ajuste em cada uma de nossas funções de clonagem, para que elas chamem o deepClone recursivamente:

    const cloneArray = (element) => {
      if (typeCheck(element) !== 'array') return element
      return element.map(deepClone)
    } 
    

    Em cloneArray, alteramos o callback de map para deepClone.

    const cloneObject = (element) => {
      if (typeCheck(element) !== 'object') return element
      return Object.fromEntries(
        Object.keys(element).map((key) => [key, deepClone(element[key])])
      )
    } 
    

    Em cloneObject, alteramos a linha 5, onde estava cloneObject para deepClone.

    Fazendo um teste final, teremos uma estrutura de dados do tipo object, com um array interno, ambos apontando para diferentes endereços de memória em relação ao endereço do objeto original "person".

    const person = {
      name: 'caique',
      age: 27,
      hobbies: [
        'movie',
        'music',
        'books'
      ]
    }
    

    console.log(deepClone(person).hobbies === person.hobbies) // false console.log(deepClone(person) === person) // false

    Recapitulando o que fizemos:

    1 - Aprendemos quais são os tipos primitivos e não primitivos do Javascript.

    2 - Aprendemos como são alocadas em memória as variáveis primitivas e não primitivas.

    3 - Implementamos uma função capaz de identificar o tipo de dado passado para ela e retornar seu valor em string.

    4 - Vimos dois tipos de paradigmas: funcional e estruturado para implementar a função cloneArray.

    5 - Criamos a função cloneObject e vimos como funciona o método Object.fromEntries.

    Bônus - Tornando nossos dados imutáveis

    A partir deste ponto somos capazes de clonar qualquer estrutura de objeto e array, mas ainda assim não escapamos do comportamento natural do Javascript, em que alteramos um dado dentro de um tipo não primitivo e esta alteração é refletida em todas as variáveis que apontam para a mesma referência.

    Nossas estruturas clonadas são mutáveis:

    const person = {
      name: 'caique',
      age: 27,
      hobbies: [
        'movie',
        'music',
        'books'
      ]
    }
    const clonedPerson = deepClone(person)
    console.log(clonedPerson === person) // false
    console.log(clonedPerson.name) // caique
    
    
    const newClonedPerson = clonedPerson
    newClonedPerson.name = 'thomas'
    
    
    

    console.log(newClonedPerson.name) // thomas console.log(clonedPerson.name) // thomas

    Mas podemos resolver esse efeito com uma simples função:

    const freeze = (data) => Object.freeze(data)
    

    A função construtora Object em Javascript, disponibiliza um método estático capaz de congelar objetos. Este congelamento impede qualquer alteração, inserção ou remoção de dados dentro da estrutura congelada. Entretanto, esse congelamento é realizado em nível superficial.

    Isso significa que a estrutura de dados interna do objeto congelado não será congelada e a mesma estará suscetível a mudanças. Para resolvermos isso teremos que partir para a recursão novamente; a boa notícia é que já deixamos o terreno pronto anteriormente. Faremos uma simples mudança em nossa função deepClone:

    const deepClone = (element) => {
      switch (typeCheck(element)) {
        case 'array':
          return freeze(cloneArray(element))
        case 'object':
          return freeze(cloneObject(element))
        default:
          return element
      }
    }
    

    Nas linhas 4 e 6 adicionamos a chamada para a função freeze, que será chamada recursivamente por meio das chamadas de deepClone.

    Nosso resultado final sobre o exemplo anterior será:

    const person = {
      name: ' caique ',
      age: 27,
      hobbies: [' movie ', ' music ', ' books '],
    }
    

    const clonedPerson = deepClone(person) console.log(clonedPerson === person) // false console.log(clonedPerson.name) // caique const newClonedPerson = clonedPerson newClonedPerson.name = ' thomas ' console.log(newClonedPerson.name) // caique console.log(clonedPerson.name) // caique

    Como podemos observar as estruturas person e clonedPerson, apesar de possuírem os mesmos valores, elas apontam para endereços de memória diferentes. E sobre a estrutura resultante (clonedPerson), se tentarmos sobrescrever alguma de suas propriedades, a mudança não acontecerá, pois nossa estrutura é imutável.

    Conclusão

    Ao longo deste artigo, exploramos um território que nos abre portas para uma série de questões a respeito de como o Javascript funciona por debaixo dos panos. Essas questões formam a bússola que aponta para o norte, onde encontram-se os melhores programadores.

    Além disso, aplicamos técnicas de programação funcional, através das quais mudamos uma instrução imperativa para uma abordagem declarativa.

    Conhecemos uma função capaz de retornar o tipo de qualquer dado passado para ela, a typeCheck, e espero que a guarde com carinho e faça bom uso.

    E pra finalizar, deixo aqui um desafio. No início do artigo eu comentei que é possível clonar estruturas de dados como arrays e objetos, e omiti intencionalmente outras estruturas nativas do Javascript como: Sets, Maps, WeakMaps e WeakSets. Como implementar funções de clonagem para essas estruturas? Sua nova missão, caso decida aceitar, é encontrar essas respostas.

    Há um tempo atrás encontrei essas respostas e desenvolvi uma biblioteca especializada em clonagem de estruturas, a Simple Immuter.

    Referências

    • JavaScript's Memory Management Explained
    • Simple Immuter
    Enquanto você pensa, a próxima geração tech já está evoluindo. Planos com até 30% OFF. Ver planos.
    Banner promocional da Alura destacando até 30% de desconto e mais 1 mês grátis para quem quer investir na carreira e acelerar sua evolução profissional. A oferta é por tempo limitado, com matrícula disponível até 24 de agosto e chamada para aproveitar a oportunidade de estudar na Alura.

    Avalie este artigo

    • Foto de Caique Moraes

      Autor(a)

      Caique Moraes

    Explore por tópico

    • Mobile
    • Back-end
    • Front-end
    • DevOps
    • UX & Design
    • Dados
    • Gestão & Negócios
    • Inteligência Artificial
    • Cibersegurança
    • Cloud

    Leia também

    • 17/02/2022

      O objeto Format Date e o formato de datas em JavaScript

      Ler mais
    • 21/04/2024

      NodeJS: OAuth por trás do código

      Ler mais
    • 28/04/2016

      O que um arquivo .java precisa para compilar?

      Ler mais
    Ver mais conteúdos

    Inscreva-se em nossa Newsletter

    Fique por dentro de conteúdos, insights e oportunidades do universo tech. Receba novidades e lançamentos direto no seu e-mail.

    Institucional

    • Sobre nós
    • Trabalhe Conosco
    • Para Empresas
    • Para Escolas
    • Política de Privacidade
    • Compromisso de Integridade
    • Termos de Uso
    • Canal de Ética
    • Código de Ética
    • Fale Conosco
    • Documentos Institucionais
    • Status
    Institucional
    • Sobre nós
    • Trabalhe Conosco
    • Para Empresas
    • Para Escolas
    • Política de Privacidade
    • Compromisso de Integridade
    • Termos de Uso
    • Canal de Ética
    • Código de Ética
    • Fale Conosco
    • Documentos Institucionais
    • Status

    A Alura

    • Como Funciona
    • Inteligência Artificial
    • Plataforma
    • Depoimentos
    • Instrutores(as)
    • Dev em <T>
    • Luri, a Inteligência Artificial da Alura
    • IA Conference
    • Cursos Imersivos
    • Perguntas Frequentes
    A Alura
    • Como Funciona
    • Inteligência Artificial
    • Plataforma
    • Depoimentos
    • Instrutores(as)
    • Dev em <T>
    • Luri, a Inteligência Artificial da Alura
    • IA Conference
    • Cursos Imersivos
    • Perguntas Frequentes

    Conteúdos

    • Alura Cases
    • Imersões
    • Artigos
    • Podcasts
    • Artigos de educação corporativa
    Conteúdos
    • Alura Cases
    • Imersões
    • Artigos
    • Podcasts
    • Artigos de educação corporativa
    Uma Empresa do GrupoLogo Grupo Alun

    Outras empresas do Grupo Alun

    • FIAP
    • STARTSE
    • PM3
    • LUMINA

    Ao submeter seu e-mail, você concorda com a política de privacidade da Alura.

    Redes Sociais & Apps

    instagram
    youtube
    tiktok
    x
    appStore
    googlePlay
    Uma Empresa do GrupoLogo Grupo Alun

    Outras empresas do Grupo Alun

    • FIAP
    • STARTSE
    • PM3
    • LUMINA

    Ao submeter seu e-mail, você concorda com a política de privacidade da Alura.

    Redes Sociais & Apps

    instagram
    youtube
    tiktok
    x
    appStore
    googlePlay
    Alura