Nota do editor: Mat Marquis e Andy Bell lançaram JavaScript para todos , um curso online oferecido exclusivamente no Piccalilli. Este post é um trecho do curso feito especificamente de um capítulo sobre desestruturação de JavaScript. Estamos publicando aqui porque acreditamos neste material e queremos incentivar pessoas como você a se inscreverem no curso. Então, aproveite esta pausa em nossa transmissão regular para ter uma pequena amostra do que você pode esperar ao se inscrever no curso completo JavaScript para todos .
Escrevo sobre JavaScript há tempo suficiente para não descartar algum tipo de maldição relacionada à arrogância. Eu escrevi JavaScript para Web Designers há mais de uma década, na época em que bandos de selvagens var ainda vagavam pela Terra. Os fundamentos são sólidos, mas o conselho está um pouco desatualizado agora, com certeza. Ainda assim, apesar de ser uma antiguidade no desenvolvimento web, uma parte do livro envelheceu particularmente bem, para minha constante frustração.
Uma linguagem de programação inteira parecia demais para ser entendida completamente, e eu tinha certeza de que não estava preparado para isso. Eu era um desenvolvedor, claro, mas não era um desenvolvedor -developer. Eu não tinha o cérebro robótico necessário; Eu apenas coloco limites nas coisas para ganhar a vida.
JavaScript para web designers
Eu ainda ouço esse sentimento de designers incrivelmente talentosos e especialistas em CSS altamente técnicos que de alguma forma não conseguem se chamar de “desenvolvedores de JavaScript”, como se tivessem nascido tragicamente sem qualquer glândula que produza os produtos químicos que fazem uma pessoa entender inatamente o conceito de elevação variável e nunca poderiam se qualificar – isso apesar do fato de que muitos deles escrevem JavaScript como parte de seu trabalho diário . Embora eu possa não aceitar o uso de alert() em alguns de meus exemplos (novamente, há muito tempo), o espírito de JavaScript para Web Designers é tão verdadeiro hoje quanto era naquela época: digite um ponto e vírgula e você estará escrevendo JavaScript. Escreva JavaScript e você será um desenvolvedor de JavaScript, ponto final.
Agora, mais cedo ou mais tarde, você se depara com o problema: ninguém nasce pensando como JavaScript, mas para tornar realmente bom em JavaScript, você precisará aprender como . Para saber por que o JavaScript funciona dessa maneira, por que às vezes coisas que parecem que deveriam funcionar não funcionam e por que coisas que parecem que não deveriam funcionar às vezes funcionam, você precisa dar um passo além do código que está escrevendo ou mesmo do resultado de executá-lo – você precisa entrar na cabeça do JavaScript. Você precisa aprender a interagir com o idioma em seus próprios termos.
Esse conhecimento mágico profundo é o objetivo de JavaScript para todos , um curso desenvolvido para ajudá-lo a passar do desenvolvedor júnior ao sênior. Em JavaScript for Everyone , meu objetivo é ajudá-lo a entender as regras mais misteriosas do JavaScript conforme ele é jogado – não apenas ensinar como mas o por que , usando as sintaxes que você provavelmente encontrará em seu trabalho diário. Se você for novo na linguagem, sairá deste curso com um conhecimento básico de JavaScript que vale centenas de horas de tentativa e erro; se você for um desenvolvedor júnior, terminará este curso com um conhecimento profundo que rivaliza com qualquer desenvolvedor sênior.
Graças aos nossos amigos aqui do CSS-Tricks, posso compartilhar a lição inteira sobre tarefa de desestruturação . Estas são algumas das minhas sintaxes JavaScript favoritas, que tenho certeza que podemos todas concordar que são normais e, na verdade, muito legais coisas para se ter – as sintaxes são tão poderosas quanto concisas, todas elas fazendo muito trabalho com apenas alguns caracteres. A desvantagem dessa concisão é que ela torna essas sintaxes um pouco mais opacas do que a maioria, especialmente quando você está armado apenas com uma guia do navegador aberta em MDN e um brilho nos olhos. Mas conseguimos isso: quando você chegar ao final desta lição, você estará descompactando estruturas de dados aninhadas complexas com o melhor delas.
E se você perdeu antes, há outro trecho do curso JavaScript para todos que cobre expressões de JavaScript disponíveis aqui em CSS-Tricks .
Tarefa de desestruturação
Ao trabalhar com uma estrutura de dados como um array ou objeto literal, você frequentemente se encontrará em uma situação em que deseja capturar alguns ou todos os valores que a estrutura contém e usá-los para inicializar variáveis discretas. Isso torna esses valores mais fáceis de trabalhar, mas historicamente falando, pode levar a um código bastante prolixo:
const theArray = [ false, true, false ]; const firstElement = theArray[0]; const secondElement = theArray[1]; const thirdElement = theArray[2];
Tudo bem! Quero dizer, funciona ; já faz trinta anos. Mas a partir do ES6 de 2015, tivemos uma opção muito mais elegante: destructuring .
A desestruturação permite extrair valores individuais de um array ou objeto e atribuí-los a um conjunto de identificadores sem a necessidade de acessar as chaves e/ou valores um de cada vez. Em sua forma mais simples – chamada desestruturação do padrão de ligação – cada valor é descompactado da matriz ou objeto literal e atribuído a um identificador correspondente, todos os quais são declarados com um único const theArray = [ false, true, false ]; const firstElement = theArray[0]; const secondElement = theArray[1]; const thirdElement = theArray[2]; ou let (ou var, tecnicamente, sim, tudo bem). Prepare-se, porque este é estranho:
const theArray = [ false, true, false ]; const [ firstElement, secondElement, thirdElement ] = theArray; console.log( firstElement ); // Result: false console.log( secondElement ); // Result: true console.log( thirdElement ); // Result: false
Isso é o que há de bom, mesmo que seja um pouco estranho ver colchetes naquele lado de um operador de atribuição. Essa ligação cobre todo o mesmo território que o trecho muito mais detalhado acima dela.
Ao trabalhar com um array, os identificadores individuais são colocados em um par de colchetes no estilo array, e cada identificador separado por vírgula que você especificar dentro desses colchetes será inicializado com o valor no elemento correspondente no Array de origem. Às vezes, você verá a desestruturação referida como descompactando uma estrutura de dados, mas apesar de como isso e “desestruturação” soam, o array ou objeto original não é modificado pelo processo.
Os elementos podem ser ignorados omitindo um identificador entre vírgulas, da mesma forma que você deixaria um valor de fora ao criar uma matriz esparsa:
const theArray = [ true, false, true ]; const [ firstElement, , thirdElement ] = theArray; console.log( firstElement ); // Result: true console.log( thirdElement ); // Result: true
Existem algumas diferenças em como você desestrutura um objeto usando a desestruturação de padrão de ligação. Os identificadores são colocados entre chaves em vez de colchetes; bastante sensato, considerando que estamos lidando com objetos. Na versão mais simples desta sintaxe, os identificadores que você usa devem corresponder às chaves de propriedade:
const theObject = { "theProperty" : true, "theOtherProperty" : false }; const { theProperty, theOtherProperty } = theObject; console.log( theProperty ); // result: true console.log( theOtherProperty ); // result: false
Um array é uma coleção indexada, e as coleções indexadas devem ser usadas de maneiras onde a ordem de iteração específica é importante – por exemplo, com a desestruturação aqui, onde podemos assumir que os identificadores que especificamos corresponderão aos elementos do array, em ordem sequencial.
Esse não é o caso de um objeto, que é uma coleção codificada – em termos técnicos estritos, apenas uma grande e velha pilha de propriedades que devem ser definidas e acessadas em qualquer ordem, com base em suas chaves. Na prática, porém, não é grande coisa; provavelmente você gostaria de usar os nomes dos identificadores das chaves de propriedade (ou algo muito semelhante) como seus identificadores de qualquer maneira. Simples e eficaz, mas a desvantagem é que ele assume uma determinada… bem, estrutura para o objeto que está sendo desestruturado.
Isso nos leva à sintaxe alternativa, que parece absolutamente selvagem , pelo menos para mim. A sintaxe é objeto literal em forma , mas muito, muito diferente – então, antes de olhar para isso, esqueça brevemente tudo o que você sabe sobre literais de objeto:
const theObject = { "theProperty" : true, "theOtherProperty" : false }; const { theProperty : theIdentifier, theOtherProperty : theOtherIdentifier } = theObject; console.log( theIdentifier ); // result: true console.log( theOtherIdentifier ); // result: false
Você ainda não está pensando na notação literal de objetos, certo? Porque se você fosse, uau essa sintaxe pareceria estranha. Quer dizer, uma referência à propriedade a ser desestruturada onde estaria uma chave e identificadores onde estariam os valores?
Felizmente, não estamos pensando nem um pouco na notação literal de objeto agora, então não preciso escrever aquele parágrafo anterior em primeiro lugar. Em vez disso, podemos enquadrá-lo assim: entre chaves entre parênteses, zero ou mais instâncias separadas por vírgula da chave de propriedade com o valor que desejamos, seguido por dois pontos, seguido pelo identificador ao qual queremos que o valor da propriedade seja atribuído. Após as chaves, um operador de atribuição (var) e o objeto a ser desestruturado. Isso tudo está muito impresso, eu sei, mas você vai ter uma ideia depois de usá-lo algumas vezes.
A segunda abordagem para desestruturação é desestruturação de padrão de atribuição . Com padrões de atribuição, o valor de cada propriedade desestruturada é atribuído a um destino específico – como uma variável que declaramos com const theArray = [ false, true, false ]; const firstElement = theArray[0]; const secondElement = theArray[1]; const thirdElement = theArray[2]; (ou, tecnicamente , var), uma propriedade de outro objeto ou um elemento em uma matriz.
Ao trabalhar com arrays e variáveis declaradas com const theArray = [ false, true, false ]; const firstElement = theArray[0]; const secondElement = theArray[1]; const thirdElement = theArray[2];, a desestruturação do padrão de atribuição realmente apenas adiciona uma etapa onde você declara as variáveis que acabarão contendo os valores desestruturados:
const theArray = [ true, false ]; let theFirstIdentifier; let theSecondIdentifier [ theFirstIdentifier, theSecondIdentifier ] = theArray; console.log( theFirstIdentifier ); // true console.log( theSecondIdentifier ); // false
Isso fornece o mesmo resultado final que você obteria usando a desestruturação do padrão de ligação, como:
const theArray = [ true, false ]; let [ theFirstIdentifier, theSecondIdentifier ] = theArray; console.log( theFirstIdentifier ); // true console.log( theSecondIdentifier ); // false
A desestruturação do padrão de ligação permitirá que você use let desde o início:
const theArray = [ true, false ]; const [ theFirstIdentifier, theSecondIdentifier ] = theArray; console.log( theFirstIdentifier ); // true console.log( theSecondIdentifier ); // false
Agora, se você quisesse usar esses valores desestruturados para preencher outro array ou as propriedades de um objeto, você encontraria uma barreira previsível de declaração dupla ao usar a desestruturação de padrão de ligação:
// Error const theArray = [ true, false ]; let theResultArray = []; let [ theResultArray[1], theResultArray[0] ] = theArray; // Uncaught SyntaxError: redeclaration of let theResultArray
Não podemos fazer const theArray = [ false, true, false ]; const firstElement = theArray[0]; const secondElement = theArray[1]; const thirdElement = theArray[2];/let/var faça qualquer coisa, menos crie variáveis; esse é o negócio deles. No exemplo acima, a primeira parte da linha é interpretada como let, e obtemos um erro: const theArray = [ true, false ]; let theFirstIdentifier; let theSecondIdentifier [ theFirstIdentifier, theSecondIdentifier ] = theArray; console.log( theFirstIdentifier ); // true console.log( theSecondIdentifier ); // false já foi declarado.
Esse problema não ocorre quando usamos a desestruturação do padrão de atribuição:
const theArray = [ true, false ]; let theResultArray = []; [ theResultArray[1], theResultArray[0] ] = theArray; console.log( theResultArray ); // result: Array [ false, true ]
Mais uma vez, esta sintaxe também se aplica a objetos, com alguns pequenos detalhes:
const theObject = { "theProperty" : true, "theOtherProperty" : false }; let theProperty; let theOtherProperty; ({ theProperty, theOtherProperty } = theObject ); console.log( theProperty ); // true console.log( theOtherProperty ); // false
Você notará um par de parênteses de desambiguação ao redor da linha onde estamos fazendo a desestruturação. Você já viu isso antes: sem o operador de agrupamento, um par de chaves em um contexto onde uma instrução é esperada é considerado uma instrução de bloco e você obtém um erro de sintaxe:
// Error const theObject = { "theProperty" : true, "theOtherProperty" : false }; let theProperty; let theOtherProperty; { theProperty, theOtherProperty } = theObject; // Uncaught SyntaxError: expected expression, got '='
Até agora, isso não está fazendo nada que a desestruturação do padrão de ligação não pudesse. Estamos usando identificadores que correspondem às chaves de propriedade, mas qualquer identificador servirá, se usarmos a sintaxe alternativa de desestruturação de objeto:
const theObject = { "theProperty" : true, "theOtherProperty" : false }; let theFirstIdentifier; let theSecondIdentifier; ({ theProperty: theFirstIdentifier, theOtherProperty: theSecondIdentifier } = theObject ); console.log( theFirstIdentifier ); // true console.log( theSecondIdentifier ); // false
Mais uma vez, nada que a desestruturação do padrão de ligação não pudesse fazer. Mas ao contrário de desestruturação de padrão de ligação, qualquer tipo de destino de atribuição funcionará com desestruturação de padrão de atribuição:
const theObject = { "theProperty" : true, "theOtherProperty" : false }; let resultObject = {}; ({ theProperty : resultObject.resultProp, theOtherProperty : resultObject.otherResultProp } = theObject ); console.log( resultObject ); // result: Object { resultProp: true, otherResultProp: false }
Com qualquer uma das sintaxes, você pode definir valores “padrão” que serão usados se um elemento ou propriedade não estiver presente ou contiver um valor const theArray = [ true, false ]; let [ theFirstIdentifier, theSecondIdentifier ] = theArray; console.log( theFirstIdentifier ); // true console.log( theSecondIdentifier ); // false explícito:
const theArray = [ true, undefined ]; const [ firstElement, secondElement = "A string.", thirdElement = 100 ] = theArray; console.log( firstElement ); // Result: true console.log( secondElement ); // Result: A string. console.log( thirdElement ); // Result: 100
const theObject = { "theProperty" : true, "theOtherProperty" : undefined }; const { theProperty, theOtherProperty = "A string.", aThirdProperty = 100 } = theObject; console.log( theProperty ); // Result: true console.log( theOtherProperty ); // Result: A string. console.log( aThirdProperty ); // Result: 100
Coisas elegantes com certeza, mas onde essa sintaxe realmente brilha é quando você está descompactando arrays e objetos aninhados. Naturalmente, nada impede você de descompactar um objeto que contém um objeto como valor de propriedade e, em seguida, descompactar esse objeto interno separadamente:
const theObject = { "theProperty" : true, "theNestedObject" : { "anotherProperty" : true, "stillOneMoreProp" : "A string." } }; const { theProperty, theNestedObject } = theObject; const { anotherProperty, stillOneMoreProp = "Default string." } = theNestedObject; console.log( stillOneMoreProp ); // Result: A string.
Mas podemos tornar este caminho mais conciso. Não precisamos descompactar o objeto aninhado separadamente — podemos descompactá-lo como parte da mesma ligação:
const theObject = { "theProperty" : true, "theNestedObject" : { "anotherProperty" : true, "stillOneMoreProp" : "A string." } }; const { theProperty, theNestedObject : { anotherProperty, stillOneMoreProp } } = theObject; console.log( stillOneMoreProp ); // Result: A string.
De um objeto dentro de um objeto até três constantes fáceis de usar em uma única linha de código.
Podemos descompactar estruturas de dados mistas de forma igualmente sucinta:
const theObject = [{ "aProperty" : true, },{ "anotherProperty" : "A string." }]; const [{ aProperty }, { anotherProperty }] = theObject; console.log( anotherProperty ); // Result: A string.
Uma sintaxe densa , não há dúvida disso – beirando até o “opaco”. Pode ser necessário um pouco de experimentação para entender isso, mas uma vez clicado, a desestruturação da atribuição oferece uma maneira incrivelmente rápida e conveniente de quebrar estruturas de dados complexas sem criar um monte de estruturas e valores de dados intermediários.
Propriedades de descanso
Em todos os exemplos acima trabalhamos com quantidades conhecidas: “transforme essas propriedades ou elementos X em variáveis Y”. Isso não corresponde à realidade de quebrar um objeto enorme e emaranhado, uma matriz lotada ou ambos.
No contexto de uma atribuição de desestruturação, reticências (isso é const, não const theArray = [ true, false ]; const [ theFirstIdentifier, theSecondIdentifier ] = theArray; console.log( theFirstIdentifier ); // true console.log( theSecondIdentifier ); // false, para meus colegas entusiastas de Unicode) seguido por um identificador (no estilo // Error const theArray = [ true, false ]; let theResultArray = []; let [ theResultArray[1], theResultArray[0] ] = theArray; // Uncaught SyntaxError: redeclaration of let theResultArray) representa uma propriedade rest — um identificador que representará o resto do array ou objeto que está sendo descompactado. Esta propriedade rest conterá todos os elementos ou propriedades restantes além daqueles que descompactamos explicitamente com seus próprios identificadores, todos agrupados no mesmo tipo de estrutura de dados que estamos descompactando:
const theArray = [ false, true, false, true, true, false ]; const [ firstElement, secondElement, ...remainingElements ] = theArray; console.log( remainingElements ); // Result: Array(4) [ false, true, true, false ]
Geralmente tento evitar usar exemplos que se aproximem muito do uso no mundo real propositalmente, onde podem ficar um pouco complicados e não quero desviar a atenção das ideias centrais – mas neste caso, “complicado” é exatamente o que estamos procurando resolver. Então, vamos usar um objeto que me é caro: (parte dos) dados que representam o primeiro boletim informativo que enviei quando comecei a escrever este curso.
const firstPost = { "id": "mat-update-1.md", "slug": "mat-update-1", "body": "Hey, great to meet you, everybody. I'm Mat — \"Wilto\" is good too — and I'm here to teach you JavaScript. Not just what JavaScript is or what JavaScript does, but the *how* and the *why* of JavaScript. The weird stuff. The *deep magic_.\n\nWell, okay, I'm not *currently* here to teach you JavaScript, but I will be soon. Right now I'm just getting things in order for the course — planning, outlining, polishing the fancy semicolons that I only take out when I'm having company over, writing like 5,000 words about `this` as a warm-up that completely got away from me, that kind of thing.", "collection": "emails", "data": { "title": "Meet your Instructor", "pubDate": "2025-05-08T09:55:00.630Z", "headingSize": "large", "showUnsubscribeLink": true, "stream": "javascript-for-everyone" } };
Muita coisa acontecendo lá. Para os fins deste exercício, suponha que isso venha de uma API externa da mesma forma que está no meu site – este não é um objeto que controlamos. Claro, podemos trabalhar com esse objeto diretamente, mas isso é um pouco complicado quando tudo o que precisamos é, por exemplo, o título e o corpo do boletim informativo:
const firstPost = { "id": "mat-update-1.md", "slug": "mat-update-1", "body": "Hey, great to meet you, everybody. I'm Mat — \"Wilto\" is good too — and I'm here to teach you JavaScript. Not just what JavaScript is or what JavaScript does, but the *how* and the *why* of JavaScript. The weird stuff. The *deep magic_.\n\nWell, okay, I'm not *currently* here to teach you JavaScript, but I will be soon. Right now I'm just getting things in order for the course — planning, outlining, polishing the fancy semicolons that I only take out when I'm having company over, writing like 5,000 words about `this` as a warm-up that completely got away from me, that kind of thing.", "data": { "title": "Meet your Instructor", "pubDate": "2025-05-08T09:55:00.630Z", "headingSize": "large", "showUnsubscribeLink": true, "stream": "javascript-for-everyone" } }; const { data : { title }, body } = firstPost; console.log( title ); // Result: Meet your Instructor console.log( body ); /* Result: Hey, great to meet you, everybody. I'm Mat — \"Wilto\" is good too — and I'm here to teach you JavaScript. Not just what JavaScript is or what JavaScript does, but the *how* and the *why* of JavaScript. The weird stuff. The *deep magic_. Well, okay, I'm not *currently* here to teach you JavaScript, but I will be soon. Right now I'm just getting things in order for the course — planning, outlining, polishing the fancy semicolons that I only take out when I'm having company over, writing like 5,000 words about `this` as a warm-up that completely got away from me, that kind of thing. */
Isso é arrumado ; algumas dúzias de caracteres e temos exatamente o que precisamos desse emaranhado. Eu sei que não vou precisar dessas propriedades let ou const para publicá-lo em meu próprio site, então eu os omito completamente – mas isso interno var objeto tem um toque notável, como se talvez se pudesse esperar que ele contivesse outras propriedades associadas a postagens futuras. Não sei quais serão essas propriedades, mas sei que vou querer todas elas embaladas de uma forma que possa usá-las facilmente. Quero a propriedade let theResultArray isoladamente, mas também quero um objeto contendo todos os resto do theResultArray propriedades, sejam elas quais forem:
const firstPost = { "id": "mat-update-1.md", "slug": "mat-update-1", "body": "Hey, great to meet you, everybody. I'm Mat — \"Wilto\" is good too — and I'm here to teach you JavaScript. Not just what JavaScript is or what JavaScript does, but the *how* and the *why* of JavaScript. The weird stuff. The *deep magic_.\n\nWell, okay, I'm not *currently* here to teach you JavaScript, but I will be soon. Right now I'm just getting things in order for the course — planning, outlining, polishing the fancy semicolons that I only take out when I'm having company over, writing like 5,000 words about `this` as a warm-up that completely got away from me, that kind of thing.", "data": { "title": "Meet your Instructor", "pubDate": "2025-05-08T09:55:00.630Z", "headingSize": "large", "showUnsubscribeLink": true, "stream": "javascript-for-everyone" } }; const { data : { title, ...metaData }, body } = firstPost; console.log( title ); // Result: Meet your Instructor console.log( metaData ); // Result: Object { pubDate: "2025-05-08T09:55:00.630Z", headingSize: "large", showUnsubscribeLink: true, stream: "javascript-for-everyone" }
Agora estamos conversando. Agora temos um objeto const theArray = [ true, false ]; let theResultArray = []; [ theResultArray[1], theResultArray[0] ] = theArray; console.log( theResultArray ); // result: Array [ false, true ] contendo tudo e qualquer coisa na propriedade var do objeto que nos foi entregue.
Ouça. Se você for como eu, mesmo que ainda não tenha entendido bem a sintaxe em si, descobrirá que há algo visceralmente satisfatório na ligação no trecho acima. Todo esse trabalho feito em uma única linha de código. É conciso, é elegante – pega o complexo e o torna simples. Essa é a coisa boa.
E ainda: talvez você também consiga ouvir, bem baixinho? Uma voz baixa, bem no fundo da sua mente, que pergunta “Eu me pergunto se existe uma maneira ainda melhor ”. Para o que estamos fazendo aqui, isoladamente, esta solução é a melhor possível – mas no que diz respeito ao vasto mundo do JavaScript: há sempre uma maneira melhor. Se você ainda não consegue ouvir, aposto que ouvirá no final do curso.
Qualquer pessoa que escreve JavaScript é um desenvolvedor de JavaScript; não há duas maneiras de fazer isso. Mas a satisfação de criar ordem a partir do caos com apenas algumas teclas e o desejo de encontrar maneiras ainda melhores de fazer isso? Essas são as características de um desenvolvedor JavaScript que deve ser considerado.
Você pode fazer mais do que apenas “sobreviver” com JavaScript; Eu sei que você pode. Você pode entender JavaScript, até os mecanismos que alimentam a linguagem – as engrenagens e molas que movem toda a camada “interativa” da web. Entender realmente o JavaScript é entender os limites de como os usuários interagem com as coisas que estamos construindo, e ampliar nossa compreensão do meio com o qual trabalhamos todos os dias aprimora todas as nossas habilidades, desde o layout até a acessibilidade, passando pelo desempenho de front-end até a tipografia. Compreender JavaScript significa menos “Eu me pergunto se é possível…” e “Acho que precisamos…” em sua tomada de decisão do dia a dia, mesmo que você não seja o responsável por escrevê-lo . Expandir nossos conjuntos de habilidades sempre nos tornará melhores – e mais valorizados profissionalmente – independentemente de nossas funções.
JavaScript é algo complicado de aprender; Eu sei disso muito bem – é por isso que escrevi JavaScript para todos . Você pode fazer isso e estou aqui para ajudar.
Espero ver você lá.
