Javascript 6

Page 1


D ISTRIBUIÇÃO

Lidel – edições técnicas, lda

Sede

R. D. Estefânia, 183, R/C Dto. – 1049-057 LISBOA Tel.: +351 213 511 448 * Fax: +351 213 522 684 Revenda: revenda@lidel.pt Exportação: depinternacional@lidel.pt Venda online: livraria@lidel.pt Marketing: marketing@lidel.pt Livraria

Av. Praia da Vitória, 14 A – 1000-247 LISBOA Tel: +351 213 511 448 * Fax: +351 213 173 259 livraria@lidel.pt

E DIÇÃO

FCA – Editora de Informática

Av. Praia da Vitória, 14 A – 1000-247 LISBOA Tel: +351 213 511 448 Email: fca@fca.pt Copyright © julho 2015 FCA – Editora de Informática, Lda. ISBN: 978-972-722-815-7 Capa: José M. Ferrão – Look-Ahead Impressão e acabamento: Tipografia Lousanense, Lda. - Lousã Depósito Legal N.º 395561/15 Livro segundo o Novo Acordo Ortográfico Todos os nossos livros passam por um rigoroso controlo de qualidade, no entanto, aconselhamos a consulta periódica do nosso site (www.fca.pt) para fazer o download de eventuais correções. Os nomes comerciais referenciados neste livro têm patente registada. Marcas Registadas de FCA – Editora de Informática, Lda. – ®

®

®

Reservados todos os direitos. Esta publicação não pode ser reproduzida, nem transmitida, no todo ou em parte, por qualquer processo eletrónico, mecânico, fotocópia, digitalização, gravação, sistema de armazenamento e disponibilização de informação, sítio Web, blogue ou outros, sem prévia autorização escrita da Editora, exceto o permitido pelo CDADC, em termos de cópia privada pela AGECOP – Associação para a Gestão da Cópia Privada, através do pagamento das respetivas taxas.


ÍNDICE GERAL 0. INTRODUÇÃO .................................................................................................. 1 0.1. O que posso encontrar neste livro?................................................................................................... 1 0.2. Requisitos ............................................................................................................................................. 1 0.3. A quem se dirige este livro? .............................................................................................................. 2 0.4. Convenções .......................................................................................................................................... 2 0.5. Organização do livro .......................................................................................................................... 2 0.5.1. Capítulo 1: História e Compatibilidade ................................................................................. 2 0.5.2. Capítulo 2: Conceitos Básicos ................................................................................................ 3 0.5.3. Capítulo 3: Funções .................................................................................................................. 3 0.5.4. Capítulo 4: Objetos e Classes .................................................................................................. 3 0.5.5. Capítulo 5: Iterators ................................................................................................................... 3 0.5.6. Capítulo 6: Símbolos ................................................................................................................ 3 0.5.7. Capítulo 7: Programação Assíncrona..................................................................................... 4 0.5.8. Capítulo 8: Módulos ................................................................................................................. 4 0.6. Suporte ................................................................................................................................................. 4 1. HISTÓRIA E COMPATIBILIDADE ........................................................................... 5 1.1. Um pouco de história ......................................................................................................................... 5 1.2. Compatibilidade ................................................................................................................................. 7 1.2.1. Browsers ...................................................................................................................................... 7 1.2.2. Traceur ........................................................................................................................................ 9 1.2.2.1. Linha de comandos ................................................................................................... 13 1.2.2.2. Gestores de tarefas (Grunt) ....................................................................................... 14 1.2.3. Ambientes de desenvolvimento ........................................................................................... 16 1.2.4. Polyfills/shims ........................................................................................................................... 17 2. CONCEITOS BÁSICOS ....................................................................................... 19 2.1. Let ....................................................................................................................................................... 19 2.2. Const ................................................................................................................................................... 24 2.3. Desestruturação ................................................................................................................................ 25 2.4. Tipo Number ..................................................................................................................................... 28 2.5. Tipo Math........................................................................................................................................... 31 2.6. Tipo String ......................................................................................................................................... 32 2.6.1. Métodos úteis .......................................................................................................................... 34 2.6.2. Template strings ........................................................................................................................ 34 2.7. Expressões regulares ........................................................................................................................ 38 2.8. Tipo Array.......................................................................................................................................... 40 2.8.1. Iterators ..................................................................................................................................... 42 2.8.2. Comprehensions ........................................................................................................................ 43 2.8.3. Typed arrays.............................................................................................................................. 44 2.9. Tipo Set............................................................................................................................................... 47 © FCA – Editora de Informática


VIII

JAVASCRIPT 6

2.9.1. Iterators ..................................................................................................................................... 49 2.10. Tipo Map .......................................................................................................................................... 50 2.10.1. Iterators ................................................................................................................................... 51 2.11. Tipos WeakSet e WeakMap ........................................................................................................... 52 3. FUNÇÕES ...................................................................................................... 55 3.1. Funções dentro de blocos ................................................................................................................. 55 3.2. Parâmetros com valores predefinidos ............................................................................................ 57 3.3. Parâmetros rest .................................................................................................................................. 60 3.4. Operador spread ................................................................................................................................. 62 3.5. Propriedade name............................................................................................................................. 63 3.6. Propriedade de metadata new.target ............................................................................................. 65 3.7. Funções arrow .................................................................................................................................... 68 3.8. Otimização de tail calls ..................................................................................................................... 74 4. OBJETOS E CLASSES ........................................................................................ 77 4.1. Categorias de objetos ........................................................................................................................ 77 4.2. Melhorias na sintaxe literal .............................................................................................................. 78 4.2.1. Inicialização de propriedade ................................................................................................. 78 4.2.2. Definição de métodos de instância....................................................................................... 79 4.2.3. Melhorias nas computed properties ......................................................................................... 80 4.2.4. Duplicação de propriedades ................................................................................................. 82 4.3. Método Object.is ............................................................................................................................... 82 4.4. Método Object.assign ....................................................................................................................... 83 4.5. Alteração do prototype ...................................................................................................................... 85 4.6. Classes ................................................................................................................................................ 87 4.6.1. Termo class .............................................................................................................................. 89 4.6.2. Termo constructor .................................................................................................................. 91 4.6.3. Termos get e set ...................................................................................................................... 92 4.6.4. Encapsulamento de campos .................................................................................................. 94 4.6.5. Métodos estáticos ................................................................................................................... 95 4.6.6. Herança .................................................................................................................................... 97 4.6.7. Override de métodos ............................................................................................................... 98 4.6.8. Acesso a membros da classe-base ........................................................................................ 99 4.6.9. Extensão de classes predefinidas ........................................................................................ 100 4.7. Proxies ............................................................................................................................................... 101 5. ITERATORS ................................................................................................. 107 5.1. O que são? ........................................................................................................................................ 107 5.2. Ciclo for of e iterables ...................................................................................................................... 109 5.3. Iterators personalizados .................................................................................................................. 111 5.4. Funções geradoras .......................................................................................................................... 113 5.5. Iterators predefinidos ...................................................................................................................... 117 5.6. Funcionalidades avançadas ........................................................................................................... 118

© FCA – Editora de Informática


ÍNDICE GERAL

IX

6. SÍMBOLOS .................................................................................................. 125 6.1. O que são? ........................................................................................................................................ 125 6.2. Símbolos no dia a dia...................................................................................................................... 125 6.3. Registo global de símbolos ............................................................................................................ 127 6.4. Enumeração de propriedades definidas por símbolos .............................................................. 129 6.5. Símbolos predefinidos .................................................................................................................... 130 6.5.1. @@toStringTag....................................................................................................................... 130 6.5.2. @@toPrimitive ....................................................................................................................... 131 6.5.3. @@iterator .............................................................................................................................. 132 6.5.4. Outros iterators ...................................................................................................................... 133 7. PROGRAMAÇÃO ASSÍNCRONA ........................................................................... 135 7.1. Introdução ao código assíncrono .................................................................................................. 135 7.2. Escrita de código assíncrono ......................................................................................................... 136 7.3. Introdução às promises .................................................................................................................... 139 7.4. Criação de promises em JavaScript 6 ............................................................................................. 143 7.5. Composição de promises ................................................................................................................. 148 7.6. Funções geradoras em cenários assíncronos ............................................................................... 150 7.7. Funções geradoras e promises ........................................................................................................ 157 8. MÓDULOS ................................................................................................... 161 8.1. Introdução ........................................................................................................................................ 161 8.2. IIFE .................................................................................................................................................... 161 8.3. CommonJS ......................................................................................................................................... 163 8.4. AMD ................................................................................................................................................. 164 8.5. Módulos no ECMAScript 6 ............................................................................................................ 167 8.5.1. Named exports......................................................................................................................... 167 8.5.2. Importação de tipos.............................................................................................................. 168 8.5.3. Tipos exportáveis.................................................................................................................. 168 8.5.4. Exportações simultâneas ..................................................................................................... 169 8.5.5. Default exports ........................................................................................................................ 170 8.5.6. Wildcard import ...................................................................................................................... 171 8.5.7. Reexportação de módulos ................................................................................................... 171 8.5.8. Dependências de módulos .................................................................................................. 171 8.5.9. Metadata ................................................................................................................................ 172 8.5.10. Loader .................................................................................................................................... 173 BIBLIOGRAFIA ................................................................................................. 175 ÍNDICE REMISSIVO ........................................................................................... 177

© FCA – Editora de Informática


© FCA – Editora de Informática


0

INTRODUÇÃO

Comȱoȱpassarȱdosȱanos,ȱaȱlinguagemȱJavaScriptȱtemȱganhoȱcadaȱvezȱmaisȱimportância.ȱDeȱ linguagemȱ secundária,ȱ usadaȱ apenasȱ noȱ desenvolvimentoȱ deȱ animaçõesȱ paraȱ páginasȱ HTMLȱ eȱ queȱ muitasȱ vezesȱ eraȱ confundidaȱ comȱ aȱ linguagemȱ Java,ȱ passouȱ aȱ serȱ umaȱ dasȱ linguagensȱ maisȱ usadasȱ noȱ mundo,ȱ capazȱ deȱ abrangerȱ diversasȱ áreas,ȱ queȱ vãoȱ desdeȱ aȱ criaçãoȱ deȱ páginasȱ Webȱ atéȱ àȱ administraçãoȱ deȱ máquinasȱ comȱ diferentesȱ sistemasȱ operativos.ȱ Portanto,ȱ nosȱ diasȱ queȱ correm,ȱ nãoȱ háȱ dúvidasȱ quantoȱ àȱ importânciaȱ daȱ linguagem,ȱ peloȱ queȱ oȱ conhecimentoȱ dasȱ suasȱ funcionalidadesȱ éȱ umaȱ maisȬvaliaȱ noȱ currículoȱdeȱqualquerȱprogramador.ȱȱ

0.1

O QUE POSSO ENCONTRAR NESTE LIVRO?

Nesteȱ livro,ȱ sãoȱ apresentadasȱ asȱ principaisȱ caraterísticasȱ eȱ funcionalidadesȱ daȱ versãoȱ 6ȱ daȱ linguagemȱ JavaScript.ȱ Aȱ novaȱ versãoȱ daȱ especificaçãoȱ introduzȱ váriasȱ novidades,ȱqueȱenglobamȱfuncionalidadesȱdeȱváriasȱáreasȱdistintas.ȱParaȱalémȱdeȱnovosȱ objetosȱeȱdeȱnovosȱmétodosȱqueȱforamȱadicionadosȱaosȱobjetosȱexistentes,ȱaȱnovaȱversãoȱ daȱ linguagemȱ introduzȱ aindaȱ váriasȱ novidadesȱ aoȱ nívelȱ daȱ sintaxeȱ (ex.:ȱ definiçãoȱ eȱ classes)ȱqueȱcontribuemȱparaȱsimplificarȱaȱescritaȱdeȱcódigoȱeȱaumentarȱaȱprodutividadeȱ doȱprogramador.ȱ

0.2

REQUISITOS

Oȱlivroȱfoiȱescritoȱparaȱpermitirȱqueȱaȱaprendizagemȱdasȱnovasȱfuncionalidadesȱ daȱ linguagemȱ possaȱ serȱ feitaȱ semȱ queȱ oȱ leitorȱ tenhaȱ deȱ usarȱ umȱ computador.ȱ Aȱ reproduçãoȱdosȱexcertosȱdeȱcódigoȱpodeȱobrigarȱaȱalgunsȱpassosȱextraȱqueȱsãoȱdescritosȱ noȱ Capítuloȱ 1.ȱ Comoȱ éȱ referidoȱ nesseȱ capítulo,ȱ essesȱ passosȱ sãoȱ temporários,ȱ jáȱ queȱ seȱ esperaȱqueȱosȱbrowsersȱatualizemȱrapidamenteȱosȱseusȱmotoresȱdeȱruntimeȱdeȱJavaScriptȱ apósȱaȱpublicaçãoȱdaȱversãoȱfinalȱdaȱespecificaçãoȱ(efetuadaȱduranteȱoȱmêsȱdeȱjunhoȱdeȱ 2015).ȱ Portanto,ȱ existeȱ mesmoȱ aȱ possibilidadeȱ deȱ nãoȱ serȱ necessárioȱ efetuarȱ qualquerȱ configuraçãoȱextraȱparaȱreproduzirȱosȱexcertosȱdeȱcódigoȱapresentadosȱnoȱlivro.ȱ ȱ

© FCA – Editora de Informática


2

JAVASCRIPT 6

0.3

A QUEM SE DIRIGE ESTE LIVRO?

EsteȱlivroȱéȱdirigidoȱaȱtodosȱaquelesȱqueȱpretendemȱcolocarȬseȱrapidamenteȱaȱparȱ deȱ todasȱ asȱ novidadesȱ introduzidasȱ pelaȱ versãoȱ 6ȱ doȱ JavaScript.ȱ Oȱ livroȱ parteȱ doȱ pressupostoȱ deȱ queȱ oȱ leitorȱ jáȱ temȱ algunsȱ conhecimentosȱ eȱ experiênciaȱ naȱ escritaȱ deȱ códigoȱnestaȱlinguagem,ȱpeloȱqueȱnãoȱsãoȱapresentadasȱquaisquerȱnoçõesȱbásicasȱouȱdeȱ introdução.ȱ Portanto,ȱ estamosȱ peranteȱ umȱ livroȱ queȱ seȱ concentraȱ apenasȱ nasȱ váriasȱ (eȱ interessantes!)ȱnovidadesȱintroduzidasȱpelaȱespecificaçãoȱHarmonyȱeȱqueȱcomplementaȱasȱ informaçõesȱintroduzidasȱpeloȱlivroȱJavaScriptȱ(tambémȱpublicadoȱpelaȱFCA).ȱ

0.4

CONVENÇÕES

Aoȱ longoȱ desteȱ livro,ȱ optouȬseȱ porȱ seguirȱ umȱ conjuntoȱ deȱ convençõesȱ queȱ facilitamȱaȱinterpretaçãoȱdoȱtextoȱeȱdoȱcódigoȱapresentados.ȱAssim,ȱtodosȱosȱexcertosȱdeȱ códigoȱsãoȱapresentadosȱnoȱformatoȱseguinte:ȱ let a = 10; let b = a + 1;

Porȱ suaȱ vez,ȱ asȱ notasȱ ouȱ observaçõesȱ importantesȱ poderãoȱ serȱ encontradasȱ noȱ interiorȱdeȱumaȱsecçãoȱsemelhanteȱàȱseguinte:ȱ ȱ

Notaȱimportanteȱ

Estaȱéȱumaȱnotaȱouȱobservaçãoȱimportante.ȱ

0.5

ORGANIZAÇÃO DO LIVRO

Esteȱ livroȱ agrupaȱ asȱ váriasȱ novidadesȱ introduzidasȱ pelaȱ novaȱ especificaçãoȱ emȱ oitoȱ capítulos,ȱ queȱ podemȱ serȱ lidosȱ sequencialmenteȱ ou,ȱ seȱ oȱ leitorȱ assimȱ oȱ preferir,ȱ alternadamenteȱ (istoȱ é,ȱ semȱ respeitarȱ aȱ ordemȱ deȱ capítulosȱ apresentada).ȱ Aȱ leituraȱ nãoȱ sequencialȱ dosȱ capítulosȱ éȱ possível,ȱ devidoȱ aoȱ factoȱ deȱ todasȱ asȱ (poucas)ȱ dependênciasȱ entreȱcapítulosȱestaremȱdevidamenteȱidentificadas.ȱ

0.5.1 CAPÍTULO 1: HISTÓRIA E COMPATIBILIDADE Oȱ principalȱ objetivoȱ desteȱ capítuloȱ éȱ prepararȱ oȱ leitorȱ paraȱ asȱ novidadesȱ introduzidasȱ pelaȱ novaȱ versãoȱ daȱ especificação.ȱ Paraȱ isso,ȱ oȱ capítuloȱ começaȱ porȱ apresentarȱumaȱbreveȱresenhaȱdaȱhistóriaȱdaȱlinguagem,ȱqueȱculminouȱcomȱaȱintroduçãoȱ daȱespecificaçãoȱHarmony,ȱpara,ȱemȱseguida,ȱseȱdebruçarȱsobreȱosȱeventuaisȱproblemasȱdeȱ © FCA – Editora de Informática


INTRODUÇÃO

3

compatibilidadeȱ (eȱ respetivasȱ soluções)ȱ queȱ podemȱ afetarȱ oȱ programadorȱ queȱ desejaȱ começarȱjáȱaȱescreverȱcódigoȱemȱJavaScriptȱ6.ȱ

0.5.2 CAPÍTULO 2: CONCEITOS BÁSICOS Esteȱcapítuloȱcomeçaȱporȱapresentarȱoȱconceitoȱdeȱâmbitoȱdeȱblocoȱassociadoȱaoȱ usoȱ dosȱ novosȱ termosȱ letȱ eȱ constȱ para,ȱ emȱ seguida,ȱ ilustrarȱ algunsȱ dosȱ benefíciosȱ inerentesȱaoȱusoȱdasȱnovasȱinstruçõesȱdeȱdesestruturação.ȱOȱcapítuloȱapresentaȱaindaȱasȱ váriasȱ novidadesȱ introduzidasȱ naȱ APIȱ (Applicationȱ Programmingȱ Interface)ȱ dosȱ objetosȱ existentesȱeȱterminaȱcomȱaȱintroduçãoȱdosȱnovosȱtiposȱSet,ȱMap,ȱWeakSetȱeȱWeakMap.ȱ

0.5.3 CAPÍTULO 3: FUNÇÕES Noȱ Capítuloȱ 3,ȱ concentramoȬnosȱ naȱ análiseȱ detalhadaȱ deȱ todasȱ asȱ funcionalidadesȱassociadasȱàȱcriaçãoȱeȱusoȱdeȱfunções.ȱNesteȱcapítulo,ȱdiscutimosȱváriosȱ tópicosȱ interessantesȱ comoȱ aȱ inicializaçãoȱ predefinidaȱ deȱ parâmetros,ȱ oȱ usoȱ deȱ parâmetrosȱrestȱouȱaȱutilizaçãoȱdoȱoperadorȱspread.ȱOȱcapítuloȱencerraȱcomȱaȱapresentaçãoȱ daȱnovaȱsintaxeȱdeȱfunçõesȱanónimas:ȱestamosȱaȱfalarȱdoȱusoȱdeȱfunçõesȱarrow.ȱ

0.5.4 CAPÍTULO 4: OBJETOS E CLASSES Depoisȱ deȱ apresentarmosȱ oȱ conceitoȱ deȱ categoria,ȱ concentramoȬnosȱ nasȱ alteraçõesȱintroduzidasȱnaȱdefiniçãoȱdeȱobjetosȱatravésȱdaȱsintaxeȱliteral.ȱParaȱalémȱdestasȱ novidades,ȱoȱcapítuloȱapresentaȱaindaȱalgunsȱdosȱnovosȱmétodosȱadicionadosȱaoȱobjetoȱ Object,ȱantesȱdeȱencerrarȱcomȱumaȱanáliseȱdetalhadaȱdasȱnovidadesȱrelacionadasȱcomȱaȱ definiçãoȱdeȱclasses.ȱ

0.5.5 CAPÍTULO 5: ITERATORS Aȱ partirȱ daȱ versãoȱ 6,ȱ oȱ JavaScriptȱ passaȱ aȱ suportarȱ oȱ conceitoȱ deȱ iteratorȱ eȱ deȱ iterable.ȱEsteȱcapítuloȱcomeçaȱporȱapresentarȱasȱvantagensȱassociadasȱaoȱusoȱdesteȱtipoȱdeȱ elementosȱ para,ȱemȱ seguida,ȱ analisarȱ todosȱ osȱ detalhesȱassociadosȱ àȱ criaçãoȱ eȱusoȱ desteȱ tipoȱdeȱelementosȱemȱJavaScript.ȱ

0.5.6 CAPÍTULO 6: SÍMBOLOS Osȱ símbolosȱ permitemȱ aȱ criaçãoȱ deȱ membrosȱ “privados”ȱ numȱ objeto.ȱ Naȱ realidade,ȱosȱmembrosȱnãoȱsãoȱprivados,ȱjáȱqueȱpodemȱserȱacedidosȱpublicamente,ȱmasȱ © FCA – Editora de Informática


4

JAVASCRIPT 6

apenasȱ porȱ quemȱ detenhaȱ umaȱ referênciaȱ paraȱ oȱ símboloȱ usadoȱ naȱ criaçãoȱ desseȱ membro.ȱ Nesteȱ capítulo,ȱ analisamosȱ todasȱ asȱ funcionalidadesȱ associadasȱ aoȱ usoȱ deȱ símbolosȱemȱJavaScript.ȱ

0.5.7 CAPÍTULO 7: PROGRAMAÇÃO ASSÍNCRONA ComȱoȱlançamentoȱdoȱJavaScriptȱ6,ȱoȱambienteȱdeȱruntimeȱpassaȱaȱdisponibilizarȱ novasȱ funcionalidades,ȱ queȱ simplificamȱ oȱ trabalhoȱ doȱ programadorȱ naȱ áreaȱ daȱ programaçãoȱ assíncrona.ȱ Nesteȱ capítulo,ȱ vemosȱ comoȱ éȱ queȱ oȱ novoȱ tipoȱ Promiseȱ eȱ asȱ funçõesȱ geradorasȱ podemȱ serȱ usadosȱ paraȱ nosȱ abstrairȱ deȱ algumaȱ daȱ complexidadeȱ inerenteȱaȱestesȱcenários.ȱ

0.5.8 CAPÍTULO 8: MÓDULOS Osȱ módulosȱ permitemȬnosȱ encapsularȱ porçõesȱ deȱ códigoȱ queȱ podemȱ serȱ consumidasȱ porȱ outrasȱ aplicações.ȱ Portanto,ȱ estamosȱ peranteȱ umȱ conceitoȱ muitoȱ interessanteȱquandoȱnecessitamos,ȱporȱexemplo,ȱdeȱcriarȱnovasȱlivrariasȱqueȱserãoȱusadasȱ porȱ outrasȱ aplicações.ȱ Nesteȱ últimoȱ capítulo,ȱ começamosȱ porȱ analisarȱ asȱ váriasȱ opçõesȱ préȬJavaScriptȱ 6ȱ usadasȱ naȱ criaçãoȱ deȱ módulosȱ para,ȱ emȱ seguida,ȱ analisarmosȱ detalhadamenteȱasȱnovidadesȱintroduzidasȱpelaȱespecificaçãoȱHarmonyȱnestaȱárea.ȱ

0.6

SUPORTE

Casoȱ oȱ leitorȱ encontreȱ informaçãoȱ queȱ lheȱ pareçaȱ incorretaȱ ouȱ tenhaȱ sugestõesȱ emȱ relaçãoȱ aoȱ conteúdoȱ deȱ algumaȱ secçãoȱ doȱ livro,ȱ nãoȱ hesiteȱ eȱenvieȱ umȱ emailȱ comȱ asȱ suasȱquestõesȱparaȱlabreu@gmail.com.ȱEventuaisȱalteraçõesȱeȱerratasȱserãoȱpublicadasȱnoȱ siteȱdaȱeditora,ȱemȱhttp://www.fca.pt.ȱȱ

© FCA – Editora de Informática


2

CONCEITOS BÁSICOS

1

Neste capítulo, vamos analisar algumas das novidades relacionadas com o âmbito de blocos introduzidas pela especificação Harmony. Para além de novos termos reservados que nos permitem definir variáveis e constantes, vamos debruçar-nos sobre as alterações efetuadas à API dos objetos predefinidos existentes e analisar detalhadamente os novos objetos nativos introduzidos pela especificação.

2.1

LET

Até ao lançamento da especificação Harmony, a definição de variáveis só podia ser feita através do uso do termo var: var a = 10; //Variavel com numero 10

As variáveis podem ser globais ou locais: tudo depende do local onde são declaradas. O conceito de âmbito costuma gerar alguma confusão nos programadores que se estão a iniciar em JavaScript. Tipicamente, as variáveis criadas em programas escritos nas chamadas linguagens da família C (isto é, com sintaxe baseada na linguagem de programação C) são introduzidas no local onde são definidas. Para além disso, o próprio conceito de âmbito costuma estar intimamente ligado ao conceito de bloco. Contudo, isso não acontece em JavaScript. Analisemos o exemplo seguinte: var idade = 20; if(idade == 30 ){ var teste = "Superior a 30!"; //teste possui valor 30 } //teste existe, mas esta undefined se condicao if for falsa

Ao analisarmos o excerto anterior, não restam grandes dúvidas quanto ao facto de a variável idade ser global. O leitor inexperiente pode também pensar que a variável teste é apenas local, já que está confinada ao interior do bloco associado ao if. Infelizmente, este raciocínio está errado, já que, em JavaScript, os âmbitos são introduzidos por funções e não por blocos delimitados por chavetas ({}). Por outras

© FCA – Editora de Informática


20

JAVASCRIPT 6

palavras, até ao lançamento do JavaScript 6, a linguagem não suportava o conceito de âmbito de bloco. Para além disso, o JavaScript usa uma técnica designada por hoisting, que faz com que a declaração de uma variável seja movida para o topo do âmbito onde ela foi definida. Portanto, o código anterior é transformado pelo ambiente de runtime no seguinte, antes de ser executado: var idade = 20; var teste; //hoisting da variavel... if(idade == 30 ){ teste = "Superior a 30!"; //teste possui valor 30 } //teste existe, mas esta undefined se condicao if for falsa

Apesar de o hoisting mover a declaração da variável para o topo do âmbito atual (neste caso, para o âmbito global), a sua inicialização continua a ser efetuada no local onde o programador a tinha definido. Ao longo dos anos, este comportamento tem apanhado vários programadores desprevenidos e tem contribuído para a introdução de vários bugs no código. Foi a pensar neste tipo de problemas que a especificação Harmony resolveu introduzir o conceito de âmbito de bloco e o termo reservado let, que permite controlar o tempo de vida de uma variável de forma mais precisa. A sintaxe do termo let segue as mesmas regras do termo var, pelo que, no exemplo anterior, podemos substituir todas as ocorrências do termo var pelo termo let, com a vantagem de que o âmbito da variável será limitado ao bloco onde ela foi definida: let idade = 20; if(idade == 30 ){ let teste = "Superior a 30!"; //teste possui valor 30 //tempo de vida limitado ao bloco do if } //teste nao existe aqui!

A substituição do termo var pelo termo reservado let faz com que o programa se porte da forma esperada. Assim, a variável idade continua a ser global (foi definida fora de um bloco, no âmbito global), mas o tempo de vida da variável teste passou a estar limitado ao bloco da instrução if. Ou seja, as declarações de variáveis definidas através de let já não são movidas para o topo do âmbito atual (como acontece com as © FCA – Editora de Informática


CONCEITOS BÁSICOS

21

definidas à custa do termo var). Na prática, isto quer dizer que apenas nos podemos referir a uma variável definida através da instrução let depois de ela ter sido efetivamente declarada: if( idade == 30 ){ //teste nao existe aqui!!! let teste = "Superior a 30!"; //teste ja existe aqui! } //teste nao existe aqui!

Se tentarmos aceder à variável teste antes da sua declaração, obtemos um erro ReferenceError, que sinaliza a inexistência dessa variável. Este erro continua a ser gerado mesmo quando recorremos ao supostamente “seguro” operador typeof no interior do bloco onde essa variável foi definida: if( idade == 30 ){ console.log( typeof teste);//gera erro let teste = "Superior a 30!"; } console.log( typeof teste); //sem erro

Note-se que esta exceção do tipo ReferenceError só é gerada no interior do bloco onde a variável foi definida através da instrução let. Fora desse bloco, a exceção deixa de ser gerada. O conceito de TDZ (temporal dead zone) O termo TDZ não é definido oficialmente pela especificação, mas costuma ser usado para designar a falta de hoisting associada ao uso de instruções let. Como a declaração efetuada com o let não está sujeita ao hoisting, a variável teste é colocada numa zona TDZ, onde permanece até ser executada a instrução de declaração. O acesso a uma variável colocada numa TDZ origina sempre a geração de uma exceção em runtime. No exemplo anterior, a zona TDZ associada à variável teste é a porção de código que vai desde a chaveta de abertura do if à declaração da variável através da instrução let (portanto, inclui apenas a instrução console.log que, por tentar aceder a uma variável que está colocada numa TDZ, acaba por levar à geração de um erro em runtime). Nesta altura importa salientar que o conceito de TDZ só é aplicável no bloco onde a variável é declarada através de let. Fora desse bloco, não existe declaração de variável. É por isso que o código que recorre ao operador typeof fora da instrução if não resulta na geração de nenhum erro de runtime.

© FCA – Editora de Informática


22

JAVASCRIPT 6

Outro aspeto interessante prende-se com o que acontece quando reutilizamos o nome de uma variável no mesmo bloco. Quando isso acontece, obtemos um erro de sintaxe: //ambito global implica mesmo bloco var a = 0; let a = 10; //erro de sintaxe

Como seria de esperar, este erro não ocorre quando declaramos a variável através da instrução let no interior de um bloco interno: var a = 0; if( a == 0){ let a = 10; //sem erro }

Neste caso, não há nenhum erro, já que a instrução let está a introduzir uma nova variável no interior de um bloco que não contém nenhuma outra variável (ou constante – mais pormenores na secção seguinte) com o mesmo nome. Portanto, neste caso a variável a declarada no interior do bloco está apenas a esconder a variável homónima definida no âmbito-pai. Uso no âmbito global Quando recorremos ao termo let para declarar variáveis globais, existe o perigo de conflito de nomes com as propriedades do objeto global do ambiente de runtime. Este perigo pode resultar numa exceção em runtime quando estamos perante propriedades definidas não configuráveis.

Um dos locais onde o uso de let produz resultados mais “positivos” é na escrita de ciclos for, conforme ilustrado no exemplo seguinte: for( let i = 0; i < 10; i++ ){ efetuaCalculo(i); //efetuar outra operacao importante }

Neste caso, a variável i é local ao corpo do ciclo for. Após terminar o ciclo for, o ambiente de runtime é obrigado a destruí-la, impedindo, assim, o seu uso fora do bloco do ciclo. Note-se que isto não aconteceria se tivéssemos declarado a variável através do termo reservado var. Nesta altura, importa ainda referir que o uso deste termo no interior do bloco de um ciclo possui um comportamento diferente do que o programador experiente em JavaScript poderia esperar. Nestes casos, cada iteração do ciclo tem acesso à sua própria variável (em vez de termos uma variável partilhada por todas as iterações). Este comportamento permite a resolução de um problema antigo ilustrado no excerto seguinte: let arr = []; © FCA – Editora de Informática


CONCEITOS BÁSICOS

23

//usamos var para ilustrar o problema "antigo" for( var i = 0; i < 3; i++ ){ arr.push( function(){ console.log(i); } ); }

Nesta altura, qual será o resultado esperado quando, por exemplo, tentamos imprimir o primeiro valor armazenado no array arr? console.log(arr[0]());//qual valor impresso?

Se a resposta do leitor for diferente de 3, então foi apanhado pela tal armadilha que referimos no parágrafo anterior. Este problema é causado pelo facto de a variável i ser partilhada pelas várias closures criadas no interior do ciclo. Como todas essas closures referenciam a mesma variável e uma vez que ela possui o valor 3 no final do ciclo, então esse será o valor impresso pela instrução anterior (este comportamento não era, com toda a certeza, o desejado, uma vez que a função deveria ter escrito o valor 0 no ecrã). Tipicamente, a solução para estes problemas passava pela introdução de um parâmetro, conforme ilustrado no excerto seguinte: for( var i = 0; i < 3; i++ ){ arr. push( (function(val){ return function(){ console.log(val); } }(i)

) );

}

No excerto anterior, recorremos a uma função que se invoca a si própria para copiar o valor da variável i em cada iteração. Esta pequena alteração é suficiente para obtermos o resultado correto (arr[0]() passa a imprimir o valor 0). Se recorrermos ao termo reservado let, então este tipo de problemas deixa de ocorrer. Isto acontece porque a especificação indica que o uso da instrução let no corpo de um ciclo for acaba por introduzir uma cópia do valor “atual” em cada iteração. Portanto, em vez de usarmos a estratégia apresentada no último excerto, podemos reutilizar o primeiro exemplo, substituindo o termo var pelo termo let: for( let i = 0; i < 3; i++ ){ arr.push( function(){ console.log(i); } ); }

A introdução do termo let tem como principal objetivo a substituição do termo var, fazendo, assim, com que o comportamento associado à declaração de variáveis seja mais parecido ao existente nas restantes linguagens da família C (esta aproximação tende © FCA – Editora de Informática


24

JAVASCRIPT 6

a facilitar o uso da linguagem por parte dos programadores provenientes do C# ou do Java). Contudo, e como vimos, o seu uso pode introduzir alguns efeitos secundários se nos limitarmos simplesmente a substituir todas as existências de var por let devido à falta de hoisting que carateriza a declaração de variáveis definidas através do let. Portanto, talvez seja boa ideia movermos todas as variáveis para o topo do bloco atual antes efetuarmos a substituição do termo var pelo termo let em aplicações escritas quando efetuarmos a conversão de código existente para JavaScript 6.

2.2

CONST

A especificação Harmony permite a definição de constantes através do uso do termo reservado const. Como seria de esperar, uma constante tem de ser sempre inicializada com um determinado valor. Dpois de inicializada, o seu valor nunca pode ser alterado. O excerto seguinte ilustra uma declaração simples de uma constante: const MAX = 10;

À semelhança do que acontece com as variáveis definidas através de let, o ciclo de vida das constantes também é definido pelo âmbito do bloco onde estas são criadas: //OUTRO inexistente { const OUTRO = 20; //OUTRO definido e inicializado }

Se tentarmos criar uma constante com o mesmo nome de outra constante ou variável no mesmo bloco onde ela foi definida, obtemos um erro em runtime: var msg = "Ola" ; let idade = 20; const msg = "Teste"; //ERRO const idade = 50;//ERRO

Se as constantes anteriores não tivessem sido definidas no mesmo bloco que as variáveis, não teríamos nenhum erro, já que essas constantes estariam apenas a esconder as variáveis definidas no âmbito exterior ao atual.

© FCA – Editora de Informática


CONCEITOS BÁSICOS

2.3

25

DESESTRUTURAÇÃO

A utilização de variáveis para armazenamento de valores de propriedades de um objeto é uma das operações mais usuais em JavaScript. Analisemos o exemplo seguinte: let pessoa = { nome: "Luis", morada: "Funchal" }; //duas variaveis para aceder a propriedades do objeto pessoa let nomePessoa = pessoa.nome, moradaPessoa = pessoa.morada;

Como esta é uma operação comum, a equipa que escreveu a especificação Harmony optou por introduzir a instrução de desestruturação. Esta instrução encarrega-se de percorrer um objeto ou array (recursivamente, se necessário), de forma a guardar os valores encontrados em variáveis. O excerto seguinte mostra como podemos recorrer a esta funcionalidade para obter os mesmos resultados produzidos pelo excerto anterior: let { nome: nomePessoa, morada: moradaPessoa } = pessoa;

À primeira vista, a sintaxe pode parecer um pouco estranha. O objeto usado para alimentar as propriedades é sempre atribuído à expressão de desestruturação (neste caso, pessoa). No que diz respeito à expressão propriamente dita, ela usa uma sintaxe muito semelhante à sintaxe literal utilizada para criar objetos (literal objects). Esta expressão efetua a correspondência entre propriedade de objeto e variável (neste caso, a variável nomePessoa deve ser iniciada com o valor da propriedade nome do objeto pessoa). A sintaxe anterior pode ser simplificada se as variáveis tiverem os mesmos nomes das propriedades. O exemplo seguinte ilustra esta opção: let { nome, morada } = pessoa;

Esta sintaxe compacta é útil quando os nomes das propriedades podem ser usados como nomes de variáveis. Como seria de esperar, a desestruturação também pode ser aplicada quando estamos perante propriedades complexas: let aluno = { nome: "Luis", codigoPostal: { codigo: "9000-000", local: "Funchal" } }; © FCA – Editora de Informática


26

JAVASCRIPT 6

let { nome, codigoPostal: {codigo: cp} } = aluno;

Após executarmos a instrução de desestruturação anterior, acabamos com duas variáveis, designadas por nome e cp, que foram inicializadas, respetivamente, com os valores "Luis" e "9000-000". Como é óbvio, poderemos simplificar a instrução se não nos importarmos de introduzir duas variáveis designadas por nome e codigo: let { nome, codigoPostal: {codigo} } = aluno; //nome === "Luis" e codigo === "9000-000"

A sintaxe de desestruturação também pode ser aplicada a arrays. Nestes casos, temos apenas de substituir as chavetas por parêntesis retos: let numeros = [1, 2, 3]; let [prim, seg, ter] = numeros;

Após executarmos a instrução de desestruturação, as variáveis prim, seg e ter possuem, respetivamente, os valores 1, 2 e 3. Se estivermos interessados em obter apenas o valor presente numa das posições do array, então temos de recorrer a vírgulas até chegarmos à posição desejada. O exemplo seguinte mostra como podemos inicializar uma variável com o elemento presente na segunda posição do array: let [,x] = arr; // x contém valor 2

As operações de desestruturação também podem ser aplicadas a arrays compostos por outros arrays: let outros = [1, 2, [3,4]]; let [a,b, [c,d]] = outros;

Neste caso, as variáveis a, b, c e d são inicializadas com os valores 1, 2, 3 e 4. Nesta altura, o leitor poderá estar a interrogar-se acerca da possibilidade de efetuar a desestruturação de objetos com propriedades que referenciam arrays. E, como seria de esperar, essas operações também são suportadas. O excerto seguinte apresenta um exemplo prático: let aluno = { nome: "Luis", disciplinas: [ "Ingles", "Matematica"]}; let { nome, disciplinas } = aluno;

Neste caso, terminámos com duas variáveis, designadas por nome e por disciplinas. Note-se que a variável disciplinas não possui uma cópia do array alunos.disciplinas, mas sim uma referência para esse array. Como é evidente, poderíamos ter terminado apenas com as variáveis que referenciam os valores mantidos no array: let {nome, disciplinas: [prim, seg] } = aluno; //nome === "Luis" © FCA – Editora de Informática


CONCEITOS BÁSICOS

27

//prim === "Ingles" //seg === "Matematica"

As operações de desestruturação também podem ser usadas noutros cenários mais exóticos. Por exemplo, podemos usá-las para trocar rapidamente os valores de duas variáveis: let x = 1, y = 2; [x,y] = [y,x];

As operações de desestruturação também são muito úteis quando criamos funções que necessitam de aceder a propriedades de objetos complexos que lhe são passados. As funções que esperam vários parâmetros opcionais costumam permitir o seu agrupamento num único objeto (tipicamente, designado por options). No interior da função, uma das primeiras operações efetuadas nesses casos passa pela recuperação dos valores passados à função. O excerto seguinte ilustra este tipo de cenários: function test(options){ options = options || {}; let nome = options.nome, idade = options.idade; //restante código } test({nome: "Luis", idade: 38});

Apesar de simples, o excerto anterior reproduz o aspeto de muitas funções utilitárias existentes em várias livrarias JavaScript. Com o uso de desestruturação, podemos simplificar o código usado nestas situações, conforme é possível verificar através do exemplo seguinte: function test({nome, idade}){ //nome e idade inicializados através //desestruturacao } test( { nome: "Luis", idade: 38});

Neste exemplo, os parâmetros nome e idade são automaticamente inicializados através de desestruturação com os valores das propriedades nome e idade do objeto passado aquando da invocação da função. Se não passássemos um dos valores, o parâmetro correspondente seria inicializado com o valor undefined. Infelizmente, a declaração do método anterior não suporta todos os cenários possíveis, já que a desestruturação de objetos origina um erro em runtime quando é aplicada sobre o valor

© FCA – Editora de Informática


28

JAVASCRIPT 6

null ou sobre o valor undefined. A solução para este problema passa pela atribuição de

um valor predefinido ao parâmetro da função: function test({nome, idade} = {}){ //nome e idade inicializados atraves //desestruturacao } test( );

Portanto, a aplicação de valores predefinidos a parâmetros que recorrem a desestruturação é recomendada, uma vez que impede a ocorrência de erros de runtime quando passamos null ou undefined. Antes de terminar, resta ainda salientar que a desestruturação também pode ser usada para inicializar constantes, conforme ilustrado no excerto seguinte: let pessoa = { nome: "Luis", morada: "Funchal" }; let { nome, morada } = pessoa;

2.4

TIPO NUMBER

O ECMAScript 5 removeu o prefixo 0 usado para identificar números octais em modo strict (isto é, quando o script é executado de acordo com um conjunto de regras mais rígidas). Com esta imposição, a especificação tentava evitar alguns erros que vitimavam os iniciantes na linguagem: //sem modo strict! let t = 010; //oops: em decimal, 8 e nao 10

No excerto anterior, a variável t é inicializada com o valor 8 (decimal) e não com o valor 10. O uso do prefixo 0 produzia o mesmo resultado quando recorríamos ao método parseInt, conforme ilustrado no excerto seguinte: parseInt("010"); //8!!! (sem modo strict ativo)

Foi a pensar nestes cenários que o ECMAScript 5 eliminou esta sintaxe literal utilizada na definição de números octais em modo strict (se tentarmos usar esta sintaxe nesse modo, obtemos um erro de sintaxe em runtime). Apesar de ter contribuído para eliminar os erros de iniciante, a verdade é que esta alteração também impediu a representação de números octais no código em modo strict, já que a especificação

© FCA – Editora de Informática


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.