Introdução ao ECMAScript 6 (ES-2015)

Introdução ao ES6



Sumário
1. Literais de modelo
2. deixe e const
3. Expressões da função de seta
4. Para ... de
5. Nomes de propriedades computados
6. Object.assign ()
7. Parâmetros de descanso
8. Parâmetros padrão
9. Atribuição de reestruturação
10. Mapa
11. Definir
12. Classes
13. Promessa
14. Iteradores
15. Geradores
16. Sumbol

Literais de modelo (sequências de modelo)


Literais de modelo são literais de string que permitem o uso de expressões internas. Com eles, você pode usar literais de múltiplas linhas e interpolação de strings.

Os literais de modelo são colocados em backticks (``) em vez de duplo ou único. Eles podem conter curingas indicados por um cifrão e chaves ($ {expression}). As expressões de substituição e o texto entre elas são passados ​​para a função. Por padrão, a função simplesmente concatena todas as partes em uma sequência. Se houver uma expressão antes da linha (aqui está a tag), a linha do modelo será chamada de "modelo de tag". Nesse caso, a expressão da tag (geralmente uma função) é chamada com o literal do modelo processado, que você pode modificar antes da saída. Para escapar da cota traseira em literais de modelo, especifique a barra invertida \.

Literais multilinhas
Os caracteres de nova linha fazem parte de literais curinga. Usando cadeias regulares, a inserção de quebra automática exigiria a seguinte sintaxe:
console.log('string text line 1\n' + 'string text line 2'); // "string text line 1 // string text line 2" 

O mesmo com o uso de literais de modelo:
 console.log(`string text line 1 string text line 2`); // "string text line 1 // string text line 2" 


Interpolação de Expressão
Para inserir expressões em cadeias regulares, você teria que usar a seguinte sintaxe:
 var a = 5; var b = 10; console.log('Fifteen is ' + (a + b) + ' and not ' + (2 * a + b) + '.'); // "Fifteen is 15 and not 20." 


Agora, com a ajuda de literais de modelo, você pode usar o `açúcar sintático`, o que torna as substituições assim mais legíveis:
 var a = 5; var b = 10; console.log(`Fifteen is ${a + b} and not ${2 * a + b}.`); // "Fifteen is 15 and not 20." 


Modelos aninhados
Às vezes, aninhar um padrão é a maneira mais curta e talvez mais legível de criar uma sequência. Basta colocar outro dentro do modelo com aspas posteriores, envolvendo-o na substituição $ {}. Por exemplo, se a expressão for verdadeira, você poderá retornar um modelo literal.
No ES5:
 var classes = 'header' classes += (isLargeScreen() ? '' : item.isCollapsed ? ' icon-expander' : ' icon-collapser'); 

No ES2015 com literais de modelo sem aninhamento:
 const classes = `header ${ isLargeScreen() ? '' : (item.isCollapsed ? 'icon-expander' : 'icon-collapser') }`; 

No ES2015 com literais de modelo aninhados:
 const classes = `header ${ isLargeScreen() ? '' : `icon-${item.isCollapsed ? 'expander' : 'collapser'}` }`; 


Modelos de tag
Uma forma estendida de literais de modelo é marcada com modelos. Eles permitem que você analise literais de modelo usando uma função O primeiro argumento dessa função contém uma matriz de valores de sequência e o restante contém expressões de substituições. Como resultado, a função deve retornar a cadeia montada (ou algo completamente diferente, como será mostrado mais adiante). O nome da função pode ser qualquer coisa.
 var person = 'Mike'; var age = 28; function myTag(strings, personExp, ageExp) { var str0 = strings[0]; // "That " var str1 = strings[1]; // " is a " // ,     // (  )    , //    (""),    . // var str2 = strings[2]; var ageStr; if (ageExp > 99){ ageStr = 'centenarian'; } else { ageStr = 'youngster'; } //     ,     return `${str0}${personExp}${str1}${ageStr}`; } var output = myTag`That ${ person } is a ${ age }`; console.log(output);// That Mike is a youngster 

A função de tag não é necessária para retornar uma string.

Linhas brutas
A propriedade bruta especial, disponível para o primeiro argumento do modelo de marca, permite obter a sequência no formato em que foi inserida, sem interpretação.
 function tag(strings) { return strings.raw[0]; } tag`string text line 1 \\n string text line 2`; //  "string text line 1 \\n string text line 2", //  'n'    '\' 

Além disso, existe um método String.raw () que retorna exatamente a mesma string de origem que a função de modelo padrão e a concatenação de string retornariam juntas.

No ECMAScript 2016, os modelos marcados seguem as regras para escapar dos seguintes caracteres:
  • Caracteres Unicode começando com "\ u", por exemplo, \ u00A9
  • Pontos de código Unicode começando com "\ u {}", por exemplo, \ u {2F804}
  • representações de caracteres hexadecimais começando com "\ x", por exemplo, \ xA9
  • representações octais de caracteres começando com "\", por exemplo, \ 251


deixe e const


O escopo das variáveis ​​declaradas pelas palavras-chave let e const é o bloco no qual elas são declaradas e todas sob os blocos. Nesse sentido, a operação da diretiva let é semelhante à da diretiva var. A principal diferença é que o escopo da variável declarada pela diretiva var é toda a função na qual ela é declarada. Além das variáveis, o valor das constantes não pode ser alterado por uma nova atribuição, nem redefinido. Ao declarar uma variável com a palavra-chave const, você deve usar o operador de atribuição para definir o valor da constante.

As constantes globais não se tornam propriedades do objeto window, diferentemente das variáveis ​​var.
É necessária a inicialização de uma constante.
Você deve especificar um valor ao mesmo tempo que a declaração (a questão é que esse valor não poderá mais ser alterado).
Declarar variáveis ​​com a palavra-chave const cria uma constante (uma nova referência nomeada para uma região da memória) que é somente leitura.
Isso não significa que o valor indicado seja inalterado, mas significa que o identificador não pode ser reatribuído. Por exemplo, se uma constante apontar para um objeto, o próprio objeto poderá ser modificado.
Os nomes das constantes não podem coincidir com os nomes das funções ou variáveis ​​do mesmo escopo.

Um exemplo da diferença entre o escopo global e o bloco:
 function myFunction() { if (true) let a = 5; console.log(a); //SyntaxError   a     if if (true) var b = 5; console.log(b); //5   b     } 


Expressões de função de seta


As expressões de função de seta têm uma sintaxe mais curta que as expressões funcionais e estão lexicamente vinculadas ao valor disso (mas não vinculadas ao seu próprio, argumentos, super ou new.target). A expressão das funções de seta não permite especificar um nome; portanto, as funções de seta são anônimas, a menos que sejam atribuídas a qualquer coisa.

Sintaxe básica
 (param1, param2, …, paramN) => { statements } (param1, param2, …, paramN) => expression // : (param1, param2, …, paramN) => { return expression; } //       : (singleParam) => { statements } singleParam => { statements } //       : () => { statements } () => expression // : () => { return expression; } 


Sintaxe estendida
 //     ,     params => ({foo: bar}) // Rest       (param1, param2, ...rest) => { statements } (param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements } //    var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c; f(); // 6 

Mais informações sobre as funções das setas, você pode encontrar aqui .

Para ... de


A instrução for ... executa um loop através de objetos iteráveis ​​(incluindo Array, Map, Set, um objeto de argumentos e similares), invocando a cada etapa da iteração os operadores para cada valor de várias propriedades do objeto.

Por que NÃO DEVE usar um loop for ... para iterar? Porque, dependendo do mecanismo, o JavaScript pode iterar em ordem aleatória, o que pode levar a resultados imprevisíveis. Se uma propriedade mudar em uma iteração e depois mudar novamente, seu valor no loop será o último valor. Uma propriedade excluída antes do ciclo chegar não participará dela. As propriedades adicionadas aos objetos no loop podem ser ignoradas. Em geral, é melhor não adicionar, modificar ou excluir uma propriedade do objeto durante a iteração, se você ainda não a passou. Não há garantia de que a propriedade adicionada será visitada pelo ciclo, alterada após as alterações e excluída após a exclusão. Além disso, a variável iterativa é uma sequência, não um número, o que significa que se você deseja fazer cálculos com a variável, precisará concatenar as sequências em vez de adicioná-las. Portanto, para evitar erros lógicos, você não deve usá-lo!

Diferentemente do loop for ... of, o loop for ... in retorna todas as propriedades enumeradas, incluindo aquelas com nomes não inteiros e herdados.

For ... da sintaxe do loop
 for (var i of arr) //for ( of ) arr[i] = "something value" 

Exemplos:
 Object.prototype.objCustom = function() {}; Array.prototype.arrCustom = function() {}; let iterable = [3, 5, 7]; iterable.foo = 'hello'; for (let i in iterable) console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom" for (let i in iterable) { if (iterable.hasOwnProperty(i)) console.log(i); //  0, 1, 2, "foo" } for (let i of iterable) console.log(i); // 3, 5, 7 

Cada objeto herdará o método objCustom e cada Matriz herdará o método arrCustom, criando-os em Object.prototype e Array.prototype. O objeto iterável herdará os métodos objCustom e arrCustom devido à herança do protótipo.

O loop exibe apenas as propriedades enumeradas do objeto iterável, na ordem em que foram criadas. Ele não imprime os valores 3, 5, 7 e hello, pois eles não são enumeráveis. Os nomes das propriedades e métodos são exibidos, por exemplo, arrCustom e objCustom.

O loop é semelhante ao anterior, mas usa hasOwnProperty () para verificar se essa propriedade do objeto é própria ou herdada. Somente propriedades próprias são exibidas. Os nomes 0, 1, 2 e foo pertencem apenas à instância do objeto (não herdada). Os métodos arrCustom e objCustom não são gerados porque são herdados.

Esse loop ignora iterável e exibe os valores do objeto iterável que são definidos no método de iteração sobre, ou seja, não as propriedades do objeto, mas os valores da matriz 3, 5, 7.

Nomes de propriedades computados


A sintaxe para declarar objetos e seus elementos suporta nomes de propriedades calculados. Isso permite adicionar uma expressão aos colchetes [] que serão avaliados como o nome da propriedade. Assemelha-se a literais de modelo.

Exemplo de nomes calculados:
 var a = () => "world"; var a = { ["a" + (10 - 6)]: { ["some" + "string"]: true, [10 + 20]: 10, [`hello ${a()}`]: a() } } 



Object.assign ()


O método Object.assign () é usado para copiar os valores de todas as suas próprias propriedades enumeradas de um ou mais objetos de origem para o objeto de destino. Após a cópia, ele retorna o objeto de destino.

O método Object.assign () copia apenas propriedades enumeradas e nativas dos objetos de origem para o objeto de destino. Ele usa o método interno [[Get]] nos objetos de origem e o método [[Set]] interno no objeto de destino, portanto também chama getters e setters. É por isso que atribui propriedades em vez de simplesmente copiar ou definir novas propriedades. Esse comportamento pode tornar o método inadequado para injetar novas propriedades no protótipo se os objetos de origem injetados contiverem getters. Em vez disso, para copiar protótipos de definições de propriedades, incluindo um sinal de sua enumeração, os métodos Object.getOwnPropertyDescriptor () e Object.defineProperty () devem ser usados.

As propriedades dos tipos de String e Symbol são copiadas.

No caso de um erro, por exemplo, quando a propriedade não é gravável, é lançada uma exceção TypeError e o objeto de destino permanece inalterado.

Observe que o método Object.assign () não lança uma exceção se os valores iniciais forem nulos ou indefinidos.

Exemplo: Clonando um Objeto
 var obj = { a: 1 }; var copy = Object.assign({}, obj); console.log(copy); // { a: 1 } 

Exemplo: Mesclando Objetos
 var o1 = { a: 1 }; var o2 = { b: 2 }; var o3 = { c: 3 }; var obj = Object.assign(o1, o2, o3); console.log(obj); // { a: 1, b: 2, c: 3 } console.log(o1); // { a: 1, b: 2, c: 3 },     . 


Parâmetros de descanso


A sintaxe dos demais parâmetros da função permite representar um conjunto ilimitado de argumentos na forma de uma matriz.

Se o último argumento da função nomeada tiver um prefixo ..., ele se tornará automaticamente uma matriz com elementos de 0 a theArgs.length, de acordo com o número real de argumentos passados ​​para a função.

Sintaxe
 function(a, b, ...theArgs) { // ... } 


Um exemplo de uso da sintaxe dos parâmetros restantes:
 function name (a, b, ...c) {} name (0, 1, 2, 3,) 

Neste exemplo, a = 0 b = 1 c [0] = 2 c [1] = 3
Se o parâmetro restante não for passado, será uma matriz vazia (diferente dos parâmetros comuns, nunca será indefinido).

Essa sintaxe pode ser usada não apenas em argumentos de função, mas também em outros lugares, por exemplo, para copiar e combinar matrizes:

 var a = [ 0, 1, 2 ]; var b = [ 3, 4, 5 ]; var c = [ ...a, ...b ]; // [ 0, 1, 2, 3, 4, 5 ] 


Parâmetros padrão


Os parâmetros padrão permitem definir parâmetros formais da função com valores padrão se a função for chamada sem argumentos ou se o parâmetro for explicitamente passado indefinido.

No JavaScript, os parâmetros de uma função que não recebem valores quando é chamada assumem o valor padrão indefinido. No entanto, em alguns casos, pode ser útil definir um valor padrão diferente. É nesses casos que as configurações padrão são pretendidas.

O valor padrão é atribuído a um parâmetro formal somente se, durante uma chamada de função, o valor desse parâmetro não foi passado ou indefinido foi explicitamente passado.

Um exemplo de uso de parâmetros padrão:
 function myFun(a=5) { return a*a; } console.log(myFun()); // 25 


Atribuição de reestruturação


A sintaxe da atribuição de desestruturação nas expressões JavaScript permite recuperar dados de matrizes ou objetos usando uma sintaxe semelhante à declaração de uma matriz ou literais em um objeto.

As expressões de declaração de objeto ou matriz fornecem uma maneira fácil de criar um pacote de dados homogêneo. Ao criar esse pacote, você tem a oportunidade de usá-lo de qualquer maneira possível. Você também pode devolvê-lo em funções.

Uma das principais maneiras de usar a atribuição destrutiva é ler a estrutura de dados com um operador, embora você possa encontrar muitos outros usos além disso.

Exemplo de atribuição destrutiva:
 var a, b, rest; [a, b] = [1, 2]; console.log(a); // 1 console.log(b); // 2 [a, b, ...rest] = [1, 2, 3, 4, 5]; console.log(a); // 1 console.log(b); // 2 console.log(rest); // [3, 4, 5] ({a, b} = {a:1, b:2}); console.log(a); // 1 console.log(b); // 2 

Você pode ver mais exemplos aqui .

Mapa


Mapa - um objeto que contém pares de valores-chave e preserva a ordem de inserção. Qualquer valor (objetos e primitivas) pode ser usado como chaves.

Um exemplo:
 var myMap = new Map(); var keyObj = {}, keyFunc = function () {}, keyString = "a string"; //   myMap.set(keyString, "value associated with 'a string'"); myMap.set(keyObj, "value associated with keyObj"); myMap.set(keyFunc, "value associated with keyFunc"); myMap.size; // 3 //   myMap.get(keyString); // "value associated with 'a string'" myMap.get(keyObj); // "value associated with keyObj" myMap.get(keyFunc); // "value associated with keyFunc" myMap.get("a string"); // "value associated with 'a string'" //   keyString === 'a string' myMap.get({}); // undefined,   keyObj !== {} myMap.get(function() {}) // undefined,   keyFunc !== function () {} 

Diferença do mapa do objeto:

  • As chaves de objeto são Linhas e Símbolos, enquanto qualquer valor pode ser uma chave de Mapa, incluindo funções, objetos e primitivas.
  • Ao contrário de Objetos, as chaves no Mapa são ordenadas. Assim, durante a iteração do mapa, as chaves são retornadas em ordem de inserção.
  • Você pode obter facilmente o número de elementos em um Mapa usando a propriedade size, enquanto o número de elementos em um Objeto pode ser determinado apenas manualmente.
  • O mapa é um objeto iterável e pode ser iterado diretamente, enquanto o objeto requer o recebimento manual da lista de chaves e sua iteração.
  • O objeto tem um protótipo e, portanto, possui um conjunto de chaves padrão, que, se descuidado, pode se cruzar com as chaves. Desde o lançamento do ES5, isso pode ser alterado usando map = Object.create (null).
  • O mapa pode ter um melhor desempenho em casos de adição ou remoção freqüentes de chaves.

Propriedades e métodos:

  • Map.prototype.size - Retorna o número de pares chave / valor em um Mapa
  • Map.prototype.set (chave, valor) - Adiciona o par passado chave \ valor ao mapa. Se a chave especificada já existir, ela será substituída pelo novo valor.
  • Map.prototype.get (key) - Retorna o valor da chave passada. Se não houver chave, o indefinido retornará
  • Map.prototype.has (key) - Retorna true se a chave passada existir e false se não existir
  • Map.prototype.delete (key) - exclui o par especificado \ key value e retorna true. Retorna false se a chave não existir.
  • Map.prototype.clear () - remove todos os pares chave / valor do mapa
  • Map.prototype.keys () - Retorna um iterador de chaves em um mapa para cada elemento
  • Map.prototype.values ​​() - Retorna um iterador de valores no Mapa para cada elemento
  • Map.prototype.entries () - Retorna um iterador da matriz [chave, valor] no Mapa para cada elemento


Definir


Permite salvar valores exclusivos de qualquer tipo, tanto primitivos quanto outros tipos de objetos.

Os objetos Set representam coleções de valores que você pode percorrer na ordem em que os elementos são inseridos. O valor de um elemento no Set pode estar presente em apenas uma instância, o que garante sua exclusividade na coleção Set.

Conjunto de propriedades e métodos de instância
  • tamanho - Retorna o número de elementos no objeto Set.
  • add (value) - adiciona um novo elemento com o valor fornecido ao objeto Set. Retorna um objeto Set.
  • clear () - Remove todos os elementos do objeto Set.
  • delete (value) - exclui o elemento associado ao valor e retorna o valor que possui (value) retornaria anteriormente. has (value) retornará false mais tarde.
  • Entradas () - Retorna um novo objeto Iterator que contém uma matriz de [valor, valor] para cada elemento no objeto Definir na ordem de inserção. Isso é armazenado de maneira semelhante ao objeto Mapa, portanto, cada entrada tem o mesmo valor para sua chave e valor aqui.
  • forEach (callbackFn [, thisArg]) - Chama callbackFn uma vez para cada valor presente no objeto Set, em ordem de inserção. Se thisArg for especificado para thisEach, será usado como o valor this para cada retorno de chamada.
  • has (value) - Retorna um valor booleano confirmando se o elemento com o valor especificado está presente no objeto Set ou não.
  • values ​​() - Retorna um novo objeto Iterator que contém os valores para cada elemento no objeto Set na ordem de inserção.

Usando o objeto Set
 var mySet = new Set(); mySet.add(1); // Set { 1 } mySet.add(5); // Set { 1, 5 } mySet.add(5); // Set { 1, 5 } mySet.add("some text"); // Set { 1, 5, 'some text' } var o = {a: 1, b: 2}; mySet.add(o); mySet.add({a: 1, b: 2}); //  o    ,      mySet.has(1); // true mySet.has(3); // false, 3     set mySet.has(5); // true mySet.has(Math.sqrt(25)); // true mySet.has("Some Text".toLowerCase()); // true mySet.has(o); // true mySet.size; // 5 mySet.delete(5); //  5  set mySet.has(5); // false, 5   mySet.size; // 4,     console.log(mySet); // Set {1, 'some text', Object {a: 1, b: 2}, Object {a: 1, b: 2}} 

Conjunto de derivação
 //    : 1, "some text", {"a": 1, "b": 2} for (let item of mySet) console.log(item); //    : 1, "some text", {"a": 1, "b": 2} for (let item of mySet.keys()) console.log(item); //    : 1, "some text", {"a": 1, "b": 2} for (let item of mySet.values()) console.log(item); //    : 1, "some text", {"a": 1, "b": 2} //(key  value    ) for (let [key, value] of mySet.entries()) console.log(key); //  Set  Array var myArr = Array.from(mySet); // [1, "some text", {"a": 1, "b": 2}] //       HTML  mySet.add(document.body); mySet.has(document.querySelector("body")); // true //   Array  Set   mySet2 = new Set([1,2,3,4]); mySet2.size; // 4 [...mySet2]; // [1,2,3,4] //      var intersection = new Set([...set1].filter(x => set2.has(x))); //      var difference = new Set([...set1].filter(x => !set2.has(x))); //   set   forEach mySet.forEach(function(value) { console.log(value); }); // 1 // 2 // 3 // 4 



Aulas


As classes em JavaScript foram introduzidas no ECMAScript 2015 e são um açúcar sintático sobre a herança de protótipo em JavaScript. A sintaxe da classe não apresenta um novo modelo orientado a objetos, mas fornece uma maneira mais simples e intuitiva de criar objetos e organizar a herança.

As classes são realmente "funções especiais", assim como você define funções (expressões e declarações de funções), você pode definir classes com: declarações de classe e expressões de classe.

A diferença entre uma declaração de função e uma declaração de classe é que uma declaração de função é içada, enquanto uma declaração de classe não é. Portanto, você deve primeiro declarar sua classe e somente trabalhar com ela, caso contrário, uma exceção do tipo ReferenceError será lançada.

Declaração de classe


A primeira maneira de definir uma classe é com uma declaração de classe. Para fazer isso, use a palavra-chave class e especifique o nome da classe (no exemplo, "myClass").
 class myClass{ constructor(height, width) { this.height = height; this.width = width; } } 

A segunda maneira de definir uma classe é a expressão de classe. Você pode criar expressões nomeadas e sem nome. No primeiro caso, o nome da expressão de classe está no escopo local da classe e pode ser obtido através das propriedades da própria classe, e não de sua instância.
 //  var myClass = class { constructor(height, width) { this.height = height; this.width = width; } }; //  var myClass = class myClass { constructor(height, width) { this.height = height; this.width = width; } }; 

As expressões de classe estão sujeitas aos mesmos problemas de elevação que as declarações de classe!

Os corpos de declaração e expressões de classe são executados no modo estrito.
O modo estrito altera a sintaxe e o comportamento do tempo de execução.
Para ser mais preciso, o modo estrito é caracterizado pelo seguinte:
  • Converter erros em exceções
  • alterações que simplificam o cálculo de uma variável em certos casos de uso de seu nome;
  • , eval arguments;
  • , «» JavaScript;


  1. .
  2. .
  3. , , .
  4. ( ).
  5. , , . , .
  6. . .
  7. A sintaxe do sistema de números octais é proibida.
  8. É proibido definir propriedades com valores primitivos.

Simplificação do trabalho com variáveis
O modo estrito simplifica a comparação do nome da variável com o local de sua definição no código.
  1. É proibido usar com. O problema com é que, em tempo de execução, qualquer nome dentro do bloco pode se referir a uma propriedade do objeto que está sendo processado ou a uma variável no contexto circundante (ou até global) - é impossível saber sobre isso de antemão. Já existe uma alternativa simples: atribuir o objeto a uma variável com um nome abreviado e acessar a propriedade desejada como propriedade dessa variável.
  2. eval () no modo estrito não adiciona novas variáveis ​​ao contexto circundante.
  3. É proibido excluir nomes simples.

Simplificação de avaliação e argumentos
O modo estrito reduz o número de esquisitices no comportamento de argumentos e avaliação, ambas as quais misturam uma certa quantidade de magia no código regular. Portanto, eval adiciona ou remove variáveis ​​e altera seus valores, e a variável argumentos pode surpreender com suas propriedades indexadas, que são referências (sinônimos) para argumentos de funções nomeadas.
  1. As palavras-chave eval e argumentos não podem ser substituídas ou modificadas.
  2. Os campos do objeto de argumentos não estão associados aos argumentos da função nomeada, mas são suas cópias duplicadas dos valores.
  3. A propriedade argumentos.callee não é suportada. No código regular, a propriedade argumentos.callee refere-se à própria função, para a qual o objeto de argumentos foi criado.

JavaScript "seguro"
Alguns sites oferecem aos usuários a capacidade de escrever JavaScript que será executado no site em nome de outros usuários. Nos navegadores, o JavaScript pode ter acesso a informações particulares, o que é uma falha de segurança no JavaScript.
  1. O valor passado para a função, pois não é convertido para o objeto no modo estrito.
  2. Não é possível "executar" a pilha JavaScript através das extensões básicas do ECMAScript.
  3. Nas funções, a propriedade argumentos não fornece mais acesso às variáveis ​​criadas dentro da função.

Você pode consultar a especificação ECMAScript 5.1 para saber mais sobre o modo Estrito.
E também documentação da Mozilla.

Construtores


O construtor é um método especial usado para criar e inicializar objetos criados usando a classe
 class Student { constructor(name) { this.name = name; } } var robert = new Student('Robert'); console.log(robert.name); // Outputs 'Robert' 

Ao criar novos objetos a partir da classe, o constructor () será iniciado, o que é necessário para inicializar os objetos.

Só pode haver um método em uma classe chamada construtor. Se a classe contiver mais de um construtor, uma exceção SyntaxError será lançada.

A super palavra-chave pode ser usada no construtor para chamar o construtor da classe pai.

Se você não definiu um método construtor, o construtor padrão será usado.
Para classes base, o construtor padrão é:
 constructor() {} 

Para classes derivadas, o construtor padrão é:
 constructor(...args) { super(...args); } 


Métodos


Sintaxe da declaração do método:
 var obj = { property([parameters]) {}, get property() {}, set property(value) {}, * generator() {} }; 

Abreviação de métodos de gerador
 var obj = { * g() { var index = 0; while(true) yield index++; } }; var it = obj.g(); console.log(it.next().value); // 0 console.log(it.next().value); // 1 


Todas as definições de método, exceto os métodos de gerador, não podem ser construtores e lançarão um TypeError se você tentar instancia-las.

Nomes de propriedades computadas
 var obj = { ["foo" + 2](){ return 2; } console.log(obj.foo2()); // 2 }; 


A palavra-chave static define métodos estáticos para uma classe. Métodos estáticos são chamados sem instanciar sua classe e não podem ser chamados em instâncias da classe.

Sintaxe de getters e setters
 class Student { constructor(name) { this.name = name; } get Name() { return this.name; } set Name(newName) { if(typeof(newName) != "string") throw new Error("Name is not a string!"); else this.name = newName; // Robert } } var robert = new Student('robert'); robert.Name = "Robert"; console.log(robert.Name); 

  • setter - Necessário para validação de parâmetros escritos (como no exemplo acima)
  • getter - Necessário para obter propriedades (embora possam ser obtidas diretamente). Não pode ter argumentos

Não há encapsulamento interno no ES6, mas você pode organizá-lo. Por exemplo, assim:

 var Student = (function () { let privateProps = new WeakMap(); class Person { constructor(name, Age) { this.name = name; // public privateProps.set(this, {age: Age}); // private } get Age() { return privateProps.get(this).age; } set Age (newAge) { privateProps.set(this, {age: newAge}); } } return Person; })(); var robert = new Student('Robert', 19); robert.Age = 20; console.log(robert.Age); // 20 


Herança


A palavra-chave extends é usada nas declarações e expressões de classe para criar uma classe que é filha de outra classe.

 class Person { constructor (age) { this.age = age; } sayAge () { return this.age; } } class Student extends Person { constructor (name, age) { super(age); this.name = name; } sayFull () { return `Hello my name is ${this.name} and I'm ${super.sayAge()} years old`; } } var robert = new Student("Robert", 19); console.log(robert.sayFull()); // Hello my name is Robert and I'm 19 years old 


No construtor, a palavra-chave super () é usada como uma função que chama o construtor pai. Ele deve ser chamado antes da primeira chamada para a palavra-chave this no corpo do construtor. A super palavra-chave também pode ser usada para chamar funções do objeto pai.

Quando você substitui os métodos da classe pai na classe filho, os métodos da classe filho serão chamados por padrão, mas você pode chamar explicitamente os métodos da classe pai usando a função super ().
 class obj { constructor(name){ this.name = name; } displayName(){ return this.name.length; } } undefined class obj_2 extends obj { constructor(name) { super(name); } displayName() { //     return [this.name, super.displayName()]; } } var Obj = new obj_2("obj_2"); console.log(Obj.displayName()); // Array [ "obj_2", 5 ] 


Estendendo objetos embutidos com extensões
Este exemplo estende um objeto Data embutido.
 class myDate extends Date { constructor() { super(); } getFormattedDate() { var months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]; return this.getDate() + '-' + months[this.getMonth()] + '-' + this.getFullYear(); } } 


Promessa


O objeto Promise é usado para cálculos adiados e assíncronos.

A promessa pode estar em três estados:
  • pendente: estado inicial, não concluído e não rejeitado.
  • (fulfilled): .
  • (rejected): .

(pending), (fulfilled), (), (rejected), . , then. ( , , .. « », , , DOM.)

Promise.prototype.then() Promise.prototype.catch() , , .
imagem

(promise)
Um objeto Promise é criado usando a nova palavra-chave e seu construtor. O construtor Promise aceita um argumento chamado função executora como argumento. Esta função deve aceitar duas funções de retorno de chamada como parâmetros. O primeiro (resolver) é chamado quando a operação assíncrona foi concluída com êxito e retornou o resultado de sua execução como um valor. O segundo retorno de chamada (rejeição) é chamado quando a operação falha e retorna um valor indicando o motivo da falha, na maioria das vezes um objeto de erro.
 const myPromise = new Promise((resolve, reject) => { //   ,    : resolve(someValue); //   //  reject("failure reason"); //  }); 

Um objeto de função com dois argumentos, resolver e rejeitar, faz com que a promessa seja bem-sucedida; o segundo a rejeita.

Para fornecer à função a funcionalidade de promessa, você só precisa retornar o objeto Promise.
 function myAsyncFunction(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onload = () => resolve(xhr.responseText); xhr.onerror = () => reject(xhr.statusText); xhr.send(); }); } 

Usando. os manipuladores de execução e rejeição são anexados.

Métodos
  • Promise.all (iterável) - Aguarda que todas as promessas sejam executadas ou rejeitadas para qualquer uma delas. Retorna uma promessa que será executada depois que todas as promessas forem executadas em iterável. Caso alguma das promessas seja rejeitada, Promise.all também será rejeitado.
  • Promise.allSettled (iterável) - Aguarda a conclusão de todas as promessas recebidas (execução e rejeição). Retorna uma promessa que é executada quando todas as promessas recebidas são concluídas (executadas ou rejeitadas), contendo uma matriz dos resultados da execução das promessas recebidas.
  • Promise.race (iterável) - Aguarda a execução ou rejeição de qualquer uma das promessas recebidas. Retorna uma promessa que será executada ou rejeitada com o resultado da execução da primeira promessa executada ou rejeitada de .iterable.
  • Promise.reject (reason) - Retorna uma promessa rejeitada devido ao motivo.
  • Promise.resolve (value) - Retorna a promessa executada com o valor do resultado.

Promise Prototype
  • catch (onRejected) - Adiciona uma função de retorno de chamada para lidar com a rejeição de uma promessa, que retorna uma nova promessa feita com o valor passado se chamado, ou o valor original de resolução se a promessa foi feita.
  • then (onFulfilled, onRejected) - Adiciona um manipulador de cumprimento e rejeição de promessa e retorna uma nova promessa executada com o valor do manipulador chamado ou o valor original se a promessa não foi processada (ou seja, se o manipulador onFulfilled ou onRejected correspondente não for uma função).


Criando uma solicitação http assíncrona:
 const URL = "https://getfestivo.com/v1/holidays?api_key=f8f42551-eb66-49d2-bcba-b8e42727ddfb&country=US&year=2019"; //  API      function asyncHttpRequest (url) { return new Promise((resolve, reject) => { //  promise if (url == undefined) //     url reject(new Error("Expected url and received nothing")); else { resolve(() => { fetch(url).then((response) => { //   return response.json(); //    JSON   }).then((myJson) => { return(console.log(myJson)); //      }); }); } } );} asyncHttpRequest(URL).then((result) => result(), (error) => console.log(error)); 



Você pode obter mais exemplos e informações sobre promessas na documentação oficial , bem como na documentação do Mozilla .

Iteradores


Processar cada item em uma coleção é uma operação muito comum. O JavaScript fornece várias maneiras de iterar sobre uma coleção, de um simples loop for a map (), filter () e compreensão de array. Iteradores e geradores implementam o conceito de enumeração diretamente no núcleo da linguagem e fornecem um mecanismo para definir o comportamento de ... de loops.

Um objeto é um iterador se puder acessar os elementos da coleção, um de cada vez, enquanto rastreia sua posição atual nessa sequência. Em JavaScript, um iterador é um objeto que fornece um método next () que retorna o próximo elemento de uma sequência. Este método retorna um objeto com duas propriedades: done e value.

Uma vez criado, o objeto iterador pode ser usado explicitamente chamando o método next ().

Iterável - Este é um objeto cujo conteúdo pode ser repetido.
O objeto iterável difere do não iterável, pois possui um método especial que retorna um objeto para acesso ao qual um símbolo especial é usado: Symbol.iterator
 Iterable { [Symbol.iterator]() } 

O objeto que retorna o método é formalmente chamado de iterador.
O iterador possui apenas um método next ()
 Iterator { next(); } 

Que retorna um objeto (vamos chamá-lo itreratorResult) com duas propriedades concluídas e valor
 IteratorResult { done, value } 

done indica se ainda existe um valor na sequência que está sendo pesquisada e o valor contém o próximo elemento da sequência.


Após a inicialização, o método next () pode ser chamado para acessar os pares de valores-chave no objeto, um por um.

Um objeto é iterável se definir um método para enumerar valores, ou seja, por exemplo, como os valores são enumerados na construção for..of. Alguns tipos internos, como Matriz ou Mapa, são iteráveis ​​por padrão, enquanto outros tipos, como Objeto, não são.

Para ser iterável, um objeto deve implementar o método iterador, o que significa que ele (ou um dos objetos da cadeia de protótipos) deve ter uma propriedade chamada Symbol.iterator.

É assim que o iterador padrão se parece:
 function makeIterator(array){ var nextIndex = 0; return { next: function(){ return nextIndex < array.length ? { value: array[nextIndex++], done: false } : { done: true }; } } } 


Geradores


Geradores são um tipo especial de função que funciona como uma fábrica de iteradores. Uma função se torna um gerador se contiver uma ou mais instruções de rendimento e usar a sintaxe da função *.

Geradores são um novo tipo de função que pode pausar sua execução e retornar um resultado intermediário e retomar a execução posteriormente.

Vejamos uma função regular que faz algumas contas e retorna um resultado:
 function myFunction (a) { a = a*2; a = a - 1; return a; } console.log(myFunction(5)); // 9 

Agora dê uma olhada em uma função de gerador semelhante:
 function* generator(a) { a = a*2; yield a; a = a - 1; yield a; } var it = generator(5); console.log(it.next().value); // 10 console.log(it.next().value); // 9</i> 

Como afirmado anteriormente, os geradores podem pausar sua execução e retornar um resultado intermediário. Este exemplo mostra que, no momento da primeira chamada, a função como se suspende sua execução no primeiro ponto de interrupção e retorna o resultado da primeira expressão. Na segunda chamada, a função continua do ponto de interrupção anterior e passa para a próxima, retornando o resultado da próxima expressão.

Os geradores de funções fornecem uma ferramenta poderosa para escrever funções sequenciais complexas.

Os geradores calculam os resultados de suas expressões de rendimento sob demanda, o que lhes permite trabalhar eficientemente com sequências com alta complexidade computacional ou mesmo sequências infinitas.

O método next () também assume um valor que pode ser usado para alterar o estado interno do gerador. O valor passado para next () será considerado o resultado da última expressão de rendimento que pausou o gerador.

Você pode forçar o gerador a lançar uma exceção chamando seu método throw () e passando o valor da exceção que deve ser lançada como um parâmetro. Essa exceção será lançada do contexto atual em pausa do gerador como se a declaração de rendimento atual em pausa fosse uma declaração de lançamento.

Se a declaração de rendimento não ocorrer durante o tratamento da exceção lançada, a exceção será passada acima através da chamada throw () e o resultado das chamadas subseqüentes para next () será a propriedade done igual a true.

Os geradores têm um método de retorno (valor) que retorna o valor fornecido e para o gerador.

Símbolo


Symbol é um tipo de dados primitivo cujas instâncias são únicas e imutáveis.

No tempo de execução do JavaScript, um valor de "símbolo" é criado chamando a função Symbol (), que cria dinamicamente um valor anônimo e exclusivo. O único uso razoável é salvar o caractere e, em seguida, usar o valor armazenado para criar a propriedade do objeto.

Quando um caractere é usado como identificador em uma atribuição de propriedade, a propriedade (por exemplo, um caractere) é anônima; e também não contável. Como a propriedade não é computável, ela não será exibida no loop "for (... in ...)" e, como a propriedade é anônima, ela não será exibida no array de resultados "Object.getOwnPropertyNames ()". O acesso a esta propriedade pode ser obtido usando o valor inicial do símbolo que a criou ou iterando através da matriz de resultados “Object.getOwnPropertySymbols ()”.


Então você pode criar uma propriedade de caractere:
 var user = { name: "Alex", [Symbol("password")]: "12hsK3I" } 

Para obter uma matriz de objetos de caractere, use a propriedade Object.getOwnPropertySymbols (obj);
Para acessar qualquer parte do seu código, use os métodos Symbol.for () e Symbol.keyFor ().

Para obter mais informações sobre o tipo de dados Sumbol, consulte a documentação oficial e também a documentação do Mozilla.

Source: https://habr.com/ru/post/pt460741/


All Articles