Noções básicas de JavaScript para iniciantes

O material, cuja tradução publicamos hoje, é dedicado aos conceitos básicos do JavaScript e destina-se a programadores iniciantes. Pode ser considerado como uma pequena referência às construções básicas de JS. Aqui, em particular, falaremos sobre o sistema de tipos de dados, sobre variáveis, sobre matrizes, sobre funções, sobre protótipos de objetos e sobre alguns outros recursos da linguagem.



Tipos de dados primitivos


Os seguintes tipos de dados primitivos estão disponíveis em JavaScript: number , boolean , string , undefined , null . Deve-se notar imediatamente que, ao trabalhar com tipos de dados primitivos, por exemplo, com literais de string, mesmo sem realizar uma conversão explícita, podemos acessar seus métodos e propriedades. O ponto aqui é que, ao tentar executar essas operações, os literais são automaticamente equipados com o invólucro de objeto apropriado.

▍ Números


O JavaScript tem apenas um tipo de número - são números de ponto flutuante de precisão dupla. Isso leva ao fato de que os resultados do cálculo de algumas expressões são aritmeticamente incorretos. Você já deve saber que em JS o valor da expressão 0.1 + 0.2 não 0.1 + 0.2 0.3 . Ao mesmo tempo, ao trabalhar com números inteiros, tais problemas não são observados, ou seja, 1 + 2 === 3 .

JavaScript tem um objeto Number , que é um invólucro de objeto para valores numéricos. Objetos do tipo Number podem ser criados usando um comando no formato var a = new Number(10) , ou você pode confiar no comportamento automático do sistema descrito acima. Isso, em particular, permite chamar métodos armazenados no Number.prototype conforme aplicado a literais numéricos:

 (123).toString();  //"123" (1.23).toFixed(1); //"1.2" 

Existem funções globais projetadas para converter valores de outros tipos em um tipo numérico. Isso é parseInt() , parseFloat() e a construção Number() , que nesse caso atua como uma função normal que executa a conversão de tipo:

 parseInt("1")       //1 parseInt("text")    //NaN parseFloat("1.234") //1.234 Number("1")         //1 Number("1.234")     //1.234 

Se durante a operação com números for obtido algo que não seja um número (durante alguns cálculos ou ao tentar converter algo em um número), o JavaScript não produzirá um erro, mas apresentará o resultado de uma operação como o valor NaN (Não é um número, não é um número). Para verificar se um determinado valor é NaN , você pode usar a função isNaN() .

As operações aritméticas de JS funcionam de uma maneira bastante familiar, mas você precisa prestar atenção ao fato de que o operador + pode executar adição de números e concatenação de strings.

 1 + 1      //2 "1" + "1"  //"11" 1 + "1"    //"11" 

▍Strings


As cadeias de JavaScript são cadeias de caracteres Unicode. Literais de string são criados colocando o texto entre aspas duplas ( "" ) ou simples ( '' ). Como já mencionado, ao trabalhar com literais de string, podemos confiar no invólucro de objeto correspondente, no protótipo do qual existem muitos métodos úteis, entre eles substring() , indexOf() , concat() .

 "text".substring(1,3) //ex "text".indexOf('x')   //2 "text".concat(" end") //text end 

Strings, como outros valores primitivos, são imutáveis. Por exemplo, o método concat() não modifica uma sequência existente, mas cria uma nova.

Values ​​Valores lógicos


O tipo de dados lógicos em JS é representado por dois valores - true e false . O idioma pode converter automaticamente vários valores em um tipo de dados lógico. Portanto, false, além do valor lógico false , são os valores null , undefined , '' (string vazia), 0 e NaN . Tudo o resto, incluindo quaisquer objetos, representa significados verdadeiros. No curso das operações lógicas, tudo o que é considerado verdadeiro é convertido em true , e tudo o que é considerado falso é convertido em false . Veja o exemplo a seguir. De acordo com os princípios acima, uma string vazia será convertida em false e false como resultado dessa execução de código, a string This is false chegará ao console.

 let text = ''; if(text) { console.log("This is true"); } else { console.log("This is false"); } 

Os objetos


Objetos são estruturas dinâmicas que consistem em pares de valores-chave. Os valores podem ter tipos de dados primitivos, podem ser objetos ou funções.

Os objetos são mais fáceis de criar usando a sintaxe literal do objeto:

 let obj = { message : "A message", doSomething : function() {} } 

As propriedades de um objeto podem ser lidas, adicionadas, editadas e excluídas a qualquer momento. Veja como fazê-lo:

  • Propriedades de leitura: object.name, object[expression] .
  • Gravando dados nas propriedades (se a propriedade que está sendo acessada não existir, será adicionada uma nova propriedade com a chave especificada): object.name = value , object[expression] = value .
  • Removendo propriedades: delete object.name , delete object[expression] .

Aqui estão alguns exemplos:

 let obj = {}; //    obj.message = "A message"; //    obj.message = "A new message"; //   delete object.message; //   

Objetos no idioma são implementados como tabelas de hash. Uma tabela de hash simples pode ser criada usando o comando Object.create(null) :

 let french = Object.create(null); french["yes"] = "oui"; french["no"]  = "non"; french["yes"];//"oui" 

Se o objeto precisar ser imutável, você poderá usar o comando Object.freeze() .

Para iterar sobre todas as propriedades de um objeto, você pode usar o comando Object.keys() :

 function logProperty(name){ console.log(name); //  console.log(obj[name]); //   } Object.keys(obj).forEach(logProperty); 

▍Comparação de valores de tipos e objetos primitivos


No trabalho prático com valores primitivos, é possível, como já mencionado, percebê-los como objetos que possuem propriedades e métodos, embora não sejam objetos. Valores primitivos são imutáveis, a estrutura interna dos objetos pode mudar.

Variáveis


No JavaScript, as variáveis ​​podem ser declaradas usando as palavras-chave var , let e const .

Usando a palavra-chave var , você pode declarar uma variável e, se necessário, inicializá-la com um determinado valor. Se a variável não for inicializada, seu valor será undefined . Variáveis ​​declaradas usando a palavra-chave var têm escopo funcional.

A palavra-chave let é muito semelhante à var , a diferença é que as variáveis ​​declaradas com a palavra-chave let têm escopo de bloco.

As variáveis ​​declaradas usando a palavra-chave const também têm um escopo de bloco, o qual, dado que os valores dessas variáveis ​​não podem ser alteradas, será mais corretamente chamado de "constantes". A palavra-chave const , que "congela" o valor de uma variável declarada usando-a, pode ser comparada com o método Object.freeze() , que "congela" objetos.

Se uma variável é declarada fora de uma função, seu escopo é global.

Matrizes


Matrizes em JavaScript são implementadas usando objetos. Como resultado, ao falar sobre matrizes, na verdade discutimos objetos semelhantes a matrizes. Você pode trabalhar com elementos de matriz usando seus índices. Os índices numéricos são convertidos em cadeias e usados ​​como nomes para acessar os valores dos elementos da matriz. Por exemplo, uma construção da forma arr[1] semelhante a uma construção da forma arr['1'] , e ambas fornecerão acesso ao mesmo valor: arr[1] === arr['1'] . De acordo com o acima, uma matriz simples declarada pelo comando let arr = ['A', 'B', 'C'] é representada como um objeto da seguinte forma:

 { '0': 'A', '1': 'B', '2': 'C' } 

A remoção de elementos da matriz usando o comando delete deixa buracos. Para evitar esse problema, você pode usar o comando splice() , mas funciona lentamente, porque, após excluir um elemento, move os elementos restantes da matriz, deslocando-os para o início da matriz, para a esquerda.

 let arr = ['A', 'B', 'C']; delete arr[1]; console.log(arr); // ['A', empty, 'C'] console.log(arr.length); // 3 

Os métodos de matriz facilitam a implementação de estruturas de dados, como pilhas e filas:

 //  let stack = []; stack.push(1);           // [1] stack.push(2);           // [1, 2] let last = stack.pop();  // [1] console.log(last);       // 2 //  let queue = []; queue.push(1);           // [1] queue.push(2);           // [1, 2] let first = queue.shift();//[2] console.log(first);      // 1 

Funções


Funções em JavaScript são objetos. As funções podem ser atribuídas a variáveis, armazenadas em objetos ou matrizes, passadas como argumentos para outras funções e retornadas de outras funções.

Existem três maneiras de declarar funções:

  • Declaração de função clássica (Declaração de Função ou Declaração de Função).
  • O uso de expressões funcionais (Function Expression), também denominadas literais funcionais (Function Literal).
  • Usando a sintaxe das funções de seta (Função de Seta).

▍ Declaração de função clássica


Com essa abordagem para declarar funções, as seguintes regras se aplicam:

  • A primeira palavra-chave em uma linha de declaração de function é function .
  • As funções devem receber um nome.
  • A função pode ser usada no código antes de sua declaração devido ao mecanismo de elevar a declaração da função ao topo do escopo em que é declarada.

Aqui está a aparência de uma declaração de função clássica:

 function doSomething(){} 

Expressions Expressões funcionais


Ao usar expressões funcionais, o seguinte deve ser considerado:

  • A palavra-chave function não é mais a primeira palavra em uma linha de declaração de função.
  • Um nome de função é opcional. É possível usar expressões funcionais anônimas e nomeadas.
  • Os comandos para invocar tais funções devem seguir os comandos para sua declaração.
  • Essa função pode ser iniciada imediatamente após a declaração usando a sintaxe de IIFE (expressão de função imediatamente chamada - chamada imediatamente expressão de função).

A expressão funcional é assim:

 let doSomething = function() {} 

▍ Funções de seta


As funções de seta, de fato, podem ser consideradas "açúcar sintático" para criar expressões funcionais anônimas. Deve-se notar que tais funções não possuem suas próprias entidades this e arguments . A declaração da função de seta tem esta aparência:

 let doSomething = () = > {}; 

▍ Maneiras de chamar funções


As funções podem ser chamadas de várias maneiras.

Chamada de função normal


 doSomething(arguments) 

Chamada de função na forma de um método de objeto


 theObject.doSomething(arguments) theObject["doSomething"](arguments) 

Chamada de função do construtor


 new doSomething(arguments) 

Chamando uma função usando o método apply ()


 doSomething.apply(theObject, [arguments]) doSomething.call(theObject, arguments) 

Chamando uma função usando o método bind ()


 let doSomethingWithObject = doSomething.bind(theObject); doSomethingWithObject(); 

As funções podem ser chamadas com mais ou menos argumentos que o número de parâmetros especificados quando foram declarados. No decorrer do trabalho da função, os argumentos "extras" serão simplesmente ignorados (embora a função tenha acesso a eles), os parâmetros ausentes receberão o valor undefined .

As funções têm dois pseudo-parâmetros: this e arguments .

▍ Palavra-chave isso


A this representa o contexto de uma função. O valor para o qual ele aponta depende de como a função foi chamada. Aqui estão os significados da palavra this chave this dependendo de como a função é chamada (eles são descritos acima com exemplos de código, cujas construções são usadas aqui):

  • A chamada de função usual é window / undefined .
  • Uma chamada de função na forma de um método de objeto é o theObject .
  • Uma chamada de função na forma de um construtor é um novo objeto.
  • Chamando uma função usando o método apply() - theObject .
  • Chamando uma função usando o método bind() - theObject .

Arguments Argumentos de palavras-chave


A palavra-chave arguments é um pseudo-parâmetro que dá acesso a todos os argumentos usados ​​para chamar a função. Parece uma matriz, mas não uma matriz. Em particular, ele não possui métodos de matriz.

 function reduceToSum(total, value){ return total + value; } function sum(){ let args = Array.prototype.slice.call(arguments); return args.reduce(reduceToSum, 0); } sum(1,2,3); 

Uma alternativa à palavra-chave arguments é a nova sintaxe para os parâmetros restantes. No exemplo a seguir, args é uma matriz que contém tudo o que foi passado para a função quando chamado.

 function sum(...args){ return args.reduce(reduceToSum, 0); } 

Retorno do operador


Uma função que não possui uma return retorno retornará undefined . Usando a palavra-chave return , preste atenção ao funcionamento do mecanismo de inserção automática de ponto e vírgula. Por exemplo, a seguinte função retornará não um objeto vazio, mas um valor undefined :

 function getObject(){ return { } } getObject() 

Para evitar um problema semelhante, o colchete de abertura deve ser colocado na mesma linha que a return :

 function getObject(){ return { } } 

Digitação dinâmica


JavaScript é uma linguagem de digitação dinâmica. Isso significa que valores específicos têm tipos, mas variáveis ​​não. Durante a execução do programa, valores de tipos diferentes podem ser gravados na mesma variável. Aqui está um exemplo de uma função que trabalha com valores de diferentes tipos:

 function log(value){ console.log(value); } log(1); log("text"); log({message : "text"}); 

Para descobrir o tipo de dados armazenados em uma variável, você pode usar o operador typeof() :

 let n = 1; typeof(n);   //number let s = "text"; typeof(s);   //string let fn = function() {}; typeof(fn);  //function 

Modelo de execução de thread único


O tempo de execução do JavaScript é de thread único. Isso, em particular, é expresso na impossibilidade de executar simultaneamente duas funções (se você não levar em conta as possibilidades de execução assíncrona de código, as quais não mencionamos aqui). O tempo de execução possui a chamada Fila de Eventos, que armazena uma lista de tarefas que precisam ser processadas. Como resultado, o problema de bloqueios de recursos mútuos não é típico para um esquema de execução de JS de thread único; portanto, o mecanismo de bloqueio não é necessário aqui. No entanto, o código que cai na fila de eventos deve ser executado rapidamente. Se você sobrecarregar com trabalho pesado, no aplicativo do navegador, no encadeamento principal, a página do aplicativo não responderá às ações do usuário e o navegador oferecerá o fechamento desta página.

Manipulação de exceção


O JavaScript possui um mecanismo para lidar com exceções. Funciona de acordo com um princípio bastante usual para esses mecanismos: o código que pode causar um erro é executado usando a construção try/catch . O código em si está no bloco try , os erros são processados ​​no catch .

É interessante notar que, às vezes, o JavaScript, em caso de emergência, não produz mensagens de erro. Isso se deve ao fato de o JS não gerar erros até a adoção do padrão ECMAScript 3.

Por exemplo, no fragmento de código a seguir, uma tentativa de alterar um objeto "congelado" falhará, mas uma exceção não será lançada.

 let obj = Object.freeze({}); obj.message = "text"; 

Alguns dos erros JS "silenciosos" aparecem no modo estrito; você pode ativá-lo usando a construção "use strict"; .

Sistema de protótipo


A base de mecanismos JS, como funções de construtor, o comando Object.create() , a palavra-chave da class , é baseada em um sistema de protótipo.
Considere o seguinte exemplo:

 let service = { doSomething : function() {} } let specializedService = Object.create(service); console.log(specializedService.__proto__ === service); //true 

Aqui, para criar um objeto specializedService , cujo protótipo era criar um objeto de service , o comando Object.create() foi usado. Como resultado, verifica-se que o método doSomething() pode ser chamado acessando o objeto specialService. Além disso, isso significa que a propriedade __proto__ do objeto __proto__ aponta para um objeto de service .

Agora crie um objeto semelhante usando a palavra-chave da class :

 class Service { doSomething(){} } class SpecializedService extends Service { } let specializedService = new SpecializedService(); console.log(specializedService.__proto__ === SpecializedService.prototype); 

Os métodos declarados na classe Service serão adicionados ao objeto Service.prototype . Instâncias da classe Service terão o mesmo protótipo ( Service.prototype ). Todas as instâncias delegarão chamadas de método ao objeto Service.prototype . Como resultado, verifica-se que os métodos são declarados apenas uma vez, no Service.prototype , após o qual são "herdados" por todas as instâncias da classe.

Chain Cadeia de protótipo


Objetos podem ser "herdeiros" de outros objetos. Cada objeto possui um protótipo, cujos métodos estão disponíveis para ele. Se você tentar acessar uma propriedade que não esteja no próprio objeto, o JavaScript começará a procurá-la na cadeia de protótipos. Esse processo continuará até que a propriedade seja encontrada ou até que a pesquisa chegue ao final da cadeia.

Sobre programação funcional em JavaScript


Em JavaScript, funções são objetos de primeira classe; a linguagem suporta o mecanismo de fechamento. Isso abre o caminho para a implementação de técnicas de programação funcional em JS. Em particular, estamos falando sobre a possibilidade de usar funções de ordem superior.

Um fechamento é uma função interna que tem acesso a variáveis ​​declaradas dentro da função pai, mesmo depois que a função pai é executada.

Uma função de ordem superior é uma função que pode assumir outras funções como argumentos, retornar funções ou fazer as duas coisas.

A programação funcional em JS é abordada em muitas publicações. Se você estiver interessado, aqui estão alguns materiais sobre este tópico dedicados a funções de primeira classe , composição , decoradores , encerramentos e legibilidade do código escrito em um estilo funcional.

Sumário


O poder do JavaScript reside na sua simplicidade. A compreensão dos mecanismos básicos da linguagem permite que o programador que usa o JS aplique esses mecanismos com mais eficácia e estabelece as bases para o seu crescimento profissional.

Caros leitores! Quais recursos do JavaScript você acha que a maioria dos novatos causa?

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


All Articles