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);
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?
