Hoje, na sétima parte da tradução do manual JavaScript, falaremos sobre a execução de código no modo estrito, sobre os recursos dessa palavra-chave, sobre eventos, módulos e cálculos matemáticos. Aqui, abordaremos os tópicos de trabalho com temporizadores e programação assíncrona.
→
Parte 1: primeiro programa, recursos de linguagem, padrões→
Parte 2: estilo do código e estrutura do programa→
Parte 3: variáveis, tipos de dados, expressões, objetos→
Parte 4: recursos→
Parte 5: matrizes e loops→
Parte 6: exceções, ponto e vírgula, literais curinga→
Parte 7: modo estrito, esta palavra-chave, eventos, módulos, cálculos matemáticos→
Parte 8: Visão geral dos recursos do ES6→
Parte 9: Visão geral dos padrões ES7, ES8 e ES9
Modo estrito
O modo estrito apareceu no padrão ES5. Nesse modo, a semântica da linguagem muda, ela visa melhorar o comportamento do JavaScript, o que leva ao fato de que o código nesse modo se comporta de maneira diferente do normal. De fato, estamos falando sobre o fato de que, nesse modo, são eliminadas as falhas, ambiguidades da linguagem, recursos obsoletos armazenados nela por razões de compatibilidade.
Ativando o modo estrito
Para usar o modo estrito em algum código, ele deve ser ativado explicitamente. Ou seja, não estamos falando sobre o fato de que este modo é usado por padrão. Tal abordagem interromperia o trabalho de inúmeros programas existentes, com base nos mecanismos da linguagem que estavam presentes desde o início, desde 1996. De fato, esforços significativos daqueles que desenvolvem padrões JavaScript visam precisamente garantir a compatibilidade, para que o código escrito com base nas versões antigas dos padrões possa ser executado nos mecanismos JS atuais. Essa abordagem pode ser considerada uma das chaves para o sucesso do JavaScript como uma linguagem para o desenvolvimento da web.
Para ativar o modo estrito, é usada uma diretiva especial que se parece com isso.
'use strict'
A diretiva escrita na forma de
"use strict"
e a mesma diretiva após a qual um ponto-e-vírgula (
'use strict';
e
"use strict";
) levará ao mesmo efeito. Essa diretiva (assim como as aspas), para que todo o código em um determinado arquivo seja executado no modo estrito, é colocada no início desse arquivo.
'use strict' const name = 'Flavio' const hello = () => 'hey'
O modo estrito pode ser ativado no nível de uma função separada. Para fazer isso, a diretiva correspondente deve ser colocada no início do código do corpo da função.
function hello() { 'use strict' return 'hey' }
Isso pode ser útil se o modo estrito precisar ser usado na base de código existente e, ao mesmo tempo, ativá-lo no nível do arquivo não for prático devido à falta de tempo para testes completos do código para todo esse arquivo.
Note-se que, se o modo estrito estiver ativado, você não poderá desativá-lo durante a execução do programa.
Considere alguns recursos do modo estrito.
▍ Combate à inicialização aleatória de variáveis globais
Já dissemos que, se você atribuir acidentalmente um determinado valor a uma variável não declarada, mesmo se o fizer no código de função, essa variável será globalizada por padrão (pertencente ao objeto global). Isso pode levar a surpresas.
Por exemplo, o código a seguir cria exatamente essa variável.
;(function() { variable = 'hey' })()
A
variable
estará disponível no escopo global após a execução do IIFE.
Se o modo estrito estiver ativado no nível desta função, o mesmo código causará um erro.
;(function() { 'use strict' variable = 'hey' })()
▍ Erros que ocorrem durante operações de atribuição
JavaScript, no modo normal, não relata erros que ocorram durante as operações de atribuição.
Por exemplo, em JS, há um valor
indefinido , que é um dos valores primitivos da linguagem e é representado pela propriedade de um objeto global
undefined
. No JS comum, esse comando é bem possível.
undefined = 1
Parece escrever uma unidade para uma determinada variável com o nome
undefined
, mas, na verdade, é uma tentativa de escrever um novo valor em uma propriedade de um objeto global que, a propósito, de acordo com o padrão, não pode ser substituído. No modo normal, embora esse comando seja possível, ele não levará a nada - ou seja, o valor
undefined
não será alterado e uma mensagem de erro não será exibida. No modo estrito, isso causará um erro. Para ver esta mensagem de erro e, ao mesmo tempo, verifique se o valor
undefined
não é substituído no modo normal, tente o seguinte código em um navegador ou em Node.js.
undefined = 1 console.log('This is '+undefined) ;(() => { 'use strict' undefined = 1 })()
O mesmo comportamento do sistema também é característico ao trabalhar com entidades como
NaN
Infinity
e
NaN
, bem como com outros semelhantes. O modo estrito permite evitar tudo isso.
Em JavaScript, você pode definir propriedades de objetos usando o método
Object.defineProperty () . Em particular, usando esse método, você pode definir propriedades que não podem ser alteradas.
const car = {} Object.defineProperty(car, 'color', { value: 'blue', writable: false }) console.log(car.color) car.color = 'yellow' console.log(car.color)
Observe o atributo
writable: false
usado ao definir a propriedade
color
.
O código acima, executado no modo normal, não levará a uma alteração na propriedade do objeto de
color
nem à saída de um erro. Uma tentativa de alterar essa propriedade no modo estrito resultará em um erro.
;(() => { 'use strict' car.color = 'red' })()
O mesmo vale para getters. Este código será executado, embora sem sucesso.
const car = { get color() { return 'blue' } } console.log(car.color) car.color = 'red' console.log(car.color)
E uma tentativa de fazer o mesmo no modo estrito causará um erro ao relatar uma tentativa de definir a propriedade de um objeto que possui apenas um getter.
;(() => { 'use strict' car.color = 'yellow' } )()
O JavaScript possui um método
Object.preventExtensions () que torna um objeto não extensível, ou seja, aquele ao qual novas propriedades não podem ser adicionadas. Ao trabalhar com esses objetos no modo usual, os mesmos recursos da linguagem que examinamos acima são manifestos.
const car = { color: 'blue' } Object.preventExtensions(car) console.log(car.model) car.model = 'Fiesta' console.log(car.model)
Aqui, ambas as tentativas de derivar uma propriedade do objeto de
model
resultarão no valor
undefined
aparecendo no console. Não havia essa propriedade no objeto; uma tentativa de criá-lo depois que o objeto foi tornado não expansível não levou a nada. A mesma ação no modo estrito resulta em uma mensagem de erro.
;(() => { 'use strict' car.owner = 'Flavio' } )()
Na mesma categoria de ações que não levam a nenhuma alteração, possivelmente esperada pelo programador, mas também não causam erros, as operações caem no decorrer das quais são feitas tentativas para atribuir determinadas propriedades a valores primitivos. Por exemplo, esse código, no modo normal, não causará um erro, mas não produzirá nenhum resultado.
let one = 1 one.prop = 2 console.log(one.prop)
O mesmo no modo estrito resultará em uma mensagem de erro indicando que a propriedade
prop
não pode ser criada no número
1
. De maneira semelhante, o sistema se comporta ao trabalhar com outros tipos de dados primitivos.
▍ Erros de exclusão de entidade
No modo normal, se você tentar excluir, usando o operador
delete , uma propriedade do objeto que não possa ser excluída, a
delete
retornará simplesmente
false
e tudo falhará silenciosamente.
delete Object.prototype
No modo estrito, um erro será gerado aqui.
Arguments Argumentos de função com o mesmo nome
As funções podem ter parâmetros com o mesmo nome, isso não causa erros (embora isso pareça um erro de quem criou essa função).
;(function(a, a, b) { console.log(a, b) })(1, 2, 3)
Esse código normalmente exibe
2 3
no console. No modo estrito, isso causará um erro.
A propósito, se durante a declaração da função de seta seus parâmetros tiverem o mesmo nome, isso, no modo normal, levará à saída de uma mensagem de erro.
▍ valores octais
Em JavaScript normal, você pode usar valores octais adicionando
0
ao início.
;(() => { console.log(010) })()
Aqui, a representação decimal do número octal
10
, isto é
8
entrará no console. Este
0
antes do número pode ser colocado aleatoriamente. No modo estrito, você não pode trabalhar com números octais especificados neste formato. Mas se você precisar usar o modo estrito e trabalhar com números octais, poderá escrevê-los no formato
0oXX
. O código a seguir também produzirá
8
.
;(() => { 'use strict' console.log(0o10) })()
WithOperador com
A instrução
with , que pode levar a confusão, não é permitida no modo estrito.
Alterar o comportamento do código no modo estrito não se limita àqueles que discutimos acima. Em particular, nesse modo, a palavra-chave this se comporta de maneira diferente, o que já encontramos e sobre o qual falaremos mais detalhadamente agora.
Recursos desta palavra-chave
A
this
, ou o contexto de execução, permite descrever o ambiente em que o código JS é executado. Seu significado depende do local de uso e se o modo estrito está ativado ou não.
▍ Palavra-chave no modo estrito
No modo estrito, o valor
this
passado para a função não é convertido para o objeto. Essa conversão não apenas requer recursos, mas também concede às funções acesso ao objeto global se elas forem chamadas com
this
conjunto para
undefined
ou
null
. Esse comportamento significa que a função pode obter acesso não autorizado ao objeto global. No modo estrito, a conversão
this
passada para a função não é executada. Para ver a diferença entre o comportamento
this
nas funções de modos diferentes, tente este código usando a diretiva
'use strict'
e sem ela.
;(function() { console.log(this) })()
ThisA palavra-chave this in method method
Um método é uma função que é referenciada em uma propriedade de objeto. A
this
em uma função refere-se a este objeto. Esta declaração pode ser ilustrada pelo seguinte exemplo.
const car = { maker: 'Ford', model: 'Fiesta', drive() { console.log(`Driving a ${this.maker} ${this.model} car!`) } } car.drive()
Nesse caso, usamos a função usual (e não a seta - isso é importante), a palavra-chave this usada na qual é automaticamente vinculada ao objeto que contém essa função.
Observe que o método acima de declarar um método de objeto é semelhante a este:
const car = { maker: 'Ford', model: 'Fiesta', drive: function() { console.log(`Driving a ${this.maker} ${this.model} car!`) } }
O mesmo comportamento da
this
em um método de objeto também pode ser observado usando a seguinte construção.
const car = { maker: 'Ford', model: 'Fiesta' } car.drive = function() { console.log(`Driving a ${this.maker} ${this.model} car!`) } car.drive()
▍ Palavra-chave isto e funções de seta
Vamos tentar reescrever o exemplo acima usando, como método de objeto, uma função de seta.
const car = { maker: 'Ford', model: 'Fiesta', drive: () => { console.log(`Driving a ${this.maker} ${this.model} car!`) } } car.drive()
Como você pode ver, aqui, em vez dos nomes do fabricante do carro e seu modelo, valores
undefined
são exibidos. O fato é que, como já dissemos,
this
na função de seta contém um link para o contexto que inclui a função.
Esta seta não pode ser vinculada a uma função de seta, mas você pode
This Vinculando isso
JavaScript tem um conceito como
this
obrigatório. Você pode fazer isso de várias maneiras. Por exemplo, ao declarar uma função, você pode vincular sua palavra-chave this a um objeto usando o método
bind()
.
const car = { maker: 'Ford', model: 'Fiesta' } const drive = function() { console.log(`Driving a ${this.maker} ${this.model} car!`) }.bind(car) drive()
Usando o mesmo método, você pode vincular outro objeto ao método de um objeto, como
this
.
const car = { maker: 'Ford', model: 'Fiesta', drive() { console.log(`Driving a ${this.maker} ${this.model} car!`) } } const anotherCar = { maker: 'Audi', model: 'A4' } car.drive.bind(anotherCar)()
Essa ligação também pode ser organizada no estágio de chamada da função usando os métodos
call()
e
apply()
.
const car = { maker: 'Ford', model: 'Fiesta' } const drive = function(kmh) { console.log(`Driving a ${this.maker} ${this.model} car at ${kmh} km/h!`) } drive.call(car, 100)
this
vinculado ao que é passado para esses métodos como o primeiro argumento. A diferença entre esses métodos é que
apply()
, como o segundo argumento, pega uma matriz com os argumentos passados para a função e
call()
pega uma lista de argumentos.
▍Sobre essa ligação em manipuladores de eventos do navegador
Nos retornos de chamada de retorno de evento,
this
aponta para o elemento HTML com o qual o evento ocorreu. Para vincular a um retorno de chamada, como
this
, algo mais, você pode usar o método
bind()
. Aqui está um exemplo para ilustrar isso.
<!DOCTYPE html> <html> <body> <button id="el">Element (this)</button> <button id="win">Window (this</button> <script> const el = document.getElementById("el") el.addEventListener('click', function () { alert(this) </script> </body> </html>
Eventos
O JavaScript no navegador usa um modelo de programação orientado a eventos. Essas ou outras ações são executadas pelo código em resposta a eventos. Nesta seção, falaremos sobre eventos e como lidar com eles.
Um evento pode ser, por exemplo, a conclusão do carregamento do DOM, o recebimento de dados executados como resultado de uma solicitação assíncrona, o clique em um elemento da página, a rolagem de uma página e a inserção de um determinado caractere no teclado. De fato, existem muitos eventos que, quando processados, o código JS da página permite resolver uma ampla gama de problemas na interação do aplicativo com os usuários, com os elementos da página e com o ambiente em que o código funciona.
Manipuladores de eventos
Você pode responder a eventos usando manipuladores de eventos, que são funções chamadas quando os eventos ocorrem.
Se necessário, para processar o mesmo evento, você pode registrar vários manipuladores que serão chamados se esse evento ocorrer. Os manipuladores de eventos podem ser registrados de várias maneiras. Considere três desses métodos.
Hand Manipuladores de eventos integrados
Atualmente, os manipuladores de eventos internos raramente são usados devido a suas limitações. Anteriormente, eles eram usados com muito mais frequência. Para definir esse manipulador de eventos, seu código é adicionado à marcação HTML do elemento como um atributo especial. No exemplo a seguir, um manipulador tão simples para o evento
onclick
que ocorre quando um botão é clicado é atribuído a um botão chamado
Button 1
.
<!DOCTYPE html> <html> <body> <button onclick="alert('Button 1!')">Button 1</button> <button onclick="doSomething()">Button 2</button> <script> function doSomething(){ const str = 'Button 2!' console.log(str) alert(str) } </script> </body> </html>
O código HTML para o
Button 2
usa uma abordagem semelhante, mas indica uma função cujo código é executado em resposta a um clique no botão. Esse código envia a string especificada para o console e exibe uma janela com o mesmo texto.
▍ Atribuindo um manipulador a uma propriedade de elemento HTML
Esse método de atribuição de manipuladores de eventos é adequado para casos em que um determinado evento de um elemento deve ter apenas um manipulador. Consiste em atribuir a função à propriedade correspondente do elemento.
Por exemplo, o objeto
window
possui um
onload
, chamado após o carregamento do código HTML da página e de todos os recursos adicionais necessários, como estilos e imagens. Se você atribuir um manipulador a esse evento, ao chamá-lo, poderá ter certeza de que o navegador carregou todo o conteúdo da página, com o qual você pode trabalhar programaticamente, sem medo de que alguns elementos da página ainda não tenham sido carregados.
window.onload = () => { alert('Hi!')
Essa abordagem é frequentemente usada ao processar solicitações XHR. Portanto, durante a configuração de uma solicitação, você pode especificar um manipulador para o evento
onreadystatechange , que será chamado quando a propriedade
readyState
mudar de estado. Aqui está um exemplo de uso dessa abordagem para carregar dados JSON de uma API pública.
<!DOCTYPE html> <html> <body> <button onclick="loadData()">Start</button> <script> function loadData (){ const xhr = new XMLHttpRequest() const method = 'GET' const url = 'https://jsonplaceholder.typicode.com/todos/1' xhr.open(method, url, true) xhr.onreadystatechange = function () { if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { console.log(xhr.responseText) } } xhr.send() } </script> </body> </html>
Para verificar se um manipulador está atribuído a um determinado evento, você pode fazer isso.
if (window.onload){}
▍Uso do método addEventListener ()
O
addEventListener()
, que já vimos, é um mecanismo moderno para atribuir manipuladores de eventos. Ele permite que você registre vários manipuladores para um único evento.
window.addEventListener('load', () => {
Observe que o navegador IE8 (e suas versões mais antigas) não suporta o
addEventListener()
. Ele usa um método
attachEvent()
semelhante. Isso deve ser levado em consideração se o seu programa oferecer suporte a navegadores desatualizados.
▍Sobre a atribuição de manipuladores de eventos a vários elementos
Você pode conectar manipuladores de eventos ao objeto de
window
para manipular eventos "globais", como pressionar botões no teclado. Ao mesmo tempo, os manipuladores de eventos são atribuídos a elementos HTML individuais, que respondem ao que acontece com esses elementos, por exemplo, clicando neles com o mouse. Portanto, o
addEventListener()
é usado com o objeto de
window
e com elementos comuns.
Object Objeto de evento
Como primeiro parâmetro, o manipulador de eventos pode levar um objeto de evento -
Event
. O conjunto de propriedades desse objeto depende do evento que ele descreve. Aqui, por exemplo, está o código que demonstra a manipulação de eventos de pressionamento de tecla do teclado usando o evento de pressionamento de tecla de um objeto de
keydown
.
<!DOCTYPE html> <html> <body> <script> window.addEventListener('keydown', event => { </script> </body> </html>
Como você pode ver, aqui, para exibir informações sobre a tecla pressionada no console, a propriedade do objeto
key
é usada. A propriedade
type
também é usada aqui, indicando o tipo de evento. Neste exemplo, estamos realmente trabalhando com um objeto
KeyboardEvent , que é usado para descrever eventos relacionados ao teclado. Este objeto é o descendente do objeto
Event . Objetos projetados para manipular uma variedade de eventos expandem os recursos de um objeto de evento padrão.
No mesmo exemplo, o objeto
MouseEvent é usado para processar eventos do mouse. No manipulador de eventos do
mousedown
, imprimimos no console o tipo de evento, o número do botão (propriedade do
button
) e as coordenadas do ponteiro no momento do clique (
clientY
clientX
e
clientY
).
O objeto
DragEvent é usado para manipular eventos que ocorrem ao arrastar elementos da página.
Entre as propriedades do objeto
Event
disponíveis em outros objetos de evento, podemos mencionar a propriedade
type
mencionada e a propriedade
target
, que apontam para o elemento DOM no qual o evento ocorreu. Um objeto
Event
possui métodos. Por exemplo, o método
createEvent()
permite criar novos eventos.
Surf Superfície do evento
Considere o seguinte exemplo.
<!DOCTYPE html> <html> <head> <style> #container { height: 100px; width: 200px; background-color: blue; } #child { height: 50px; width: 100px; background-color: green; } </style> </head> <body> <div id="container"> <div id="child"> </div> </div> <script> const contDiv = document.getElementById('container') contDiv.addEventListener('click', event => { console.log('container') }) const chDiv = document.getElementById('child') chDiv.addEventListener('click', event => { console.log('child') }) window.addEventListener('click', event => { console.log('window') }) </script> </body> </html>
Se você abrir a página com esse código no navegador, abra o console e clique no mouse primeiro na área livre da página, depois no retângulo azul e depois em verde, o seguinte será exibido no console:
window container window child container window
Evento borbulhandoO que pode ser observado aqui é chamado de bolhas de eventos. Ou seja, o evento que ocorre no elemento filho se estende ao elemento pai. Esse processo continua até o evento atingir o elemento "top". Se os elementos pelos quais o evento pop-up passa tiverem manipuladores correspondentes definidos, eles serão chamados de acordo com a ordem da distribuição do evento.
A
stopPropagation()
eventos pode ser interrompida usando o método
stopPropagation()
do objeto de
stopPropagation()
. Por exemplo, se for necessário que, depois de clicar no elemento
child
, o evento correspondente não se propague mais, precisamos reescrever o código no qual atribuímos o manipulador de eventos
click
seguinte forma.
chDiv.addEventListener('click', event => { console.log('child') event.stopPropagation() })
, , — , —
container
, —
child
, .
window container window child
▍
, .
load
load
window
. , , HTML-
body
.
click
.
dblclick
— .
click
dblclick
,
click
, —
dblclick
.
mousedown
,
mousemove
,
mouseup
, . ,
mousemove
, , , . , - , . .
keydown
. , . —
keyup
.
scroll
scroll
window
. , , ,
window.scrollY
.
, ,
mousemove
, .
mousemove
scroll
. - . . «» (throttling),
Lodash . , , , , . .
let cached = null window.addEventListener('mousemove', event => { if (!cached) { setTimeout(() => {
,
mousemove
, 100 .
ES-
ES6 , ES-. , , -, , Node.js, .
, . , , . , , .
Node.js CommonJS. , ES-, , . , , ES-, , , , . ,
caniuse.com , 2018 ES- 80%.
ES-
Node.js.
▍ ES-
Node.js ES- .
import package from 'module-name'
CommonJS- .
const package = require('module-name')
, JavaScript-, - . Isso é feito usando a palavra-chave
export
. , , , ,
uppercase.js
. .
export default str => str.toUpperCase()
, . .
( , ) .
HTML- ,
<script>
type="module"
.
<script type="module" src="index.js"></script>
,
(defer) . , ,
uppercase.js
, , , . -. , -. , VSCode, Live Server ( — ritwickdey.liveserver).
<!DOCTYPE html> <html> <head> </head> <body> <script type="module"> import toUpperCase from './uppercase.js' console.log(toUpperCase('hello')) </script> </body> </html>
HELLO
.
URL.
import toUpperCase from 'https://flavio-es-modules-example.glitch.me/uppercase.js'
, ,
./
/
.
▍
, .
export default str => str.toUpperCase()
.
const a = 1 const b = 2 const c = 3 export { a, b, c }
module.js
, , , .
<html> <head> </head> <body> <script type="module"> import * as m from './module.js' console.log(ma, mb, mc) </script> </body> </html>
1 2 3
.
, , .
import { a } from './module.js' import { a, b } from './module.js'
, , .
console.log(a)
:
import { a, b as two } from './module.js'
, , , , .
module.js
.
const a = 1 const b = 2 const c = 3 export { a, b, c } export default () => console.log('hi')
.
import sayHi, { a } from './module.js' console.log(a) sayHi()
.
▍CORS
CORS . , CORS, (
Access-Control-Allow-Origin: *
).
▍ nomodule
, , ,
script ,
nomodule
. , , .
<script type="module" src="module.js"></script> <script nomodule src="fallback.js"></script>
▍ ES6 WebPack
ES6 — , , ECMAScript. , , , , . ,
WebPack, , , .
▍ CommonJS
, Node.js CommonJS. , . CommonJS npm.
CommonJS-, , . ,
up-node.js
.
exports.uppercase = str => str.toUpperCase()
, .
const up = require('./up-node.js') console.log(up.uppercase('hello'))
HELLO
.
, npm, , .
const package = require('module-name')
CommonJS , . .
CommonJS- .
exports.a = 1 exports.b = 2 exports.c = 3
, .
const { a, b, c } = require('./up-node.js')
, JavaScript — .
Math
, . , , JS- .
▍
(+)
+
. :
const three = 1 + 2
, , , .
'three' + 1
(-)
const two = 4 - 2
(/)
.
20 / 5
0, .
Infinity
( ) -
Infinity
( ).
1 / 0
(%)
%
, .
20 % 5
0
NaN
(Not a Number — ).
1 % 0
(*)
1 * 2
(**)
, .
1 ** 2
▍
(++)
++
1
. .
—
1
, .
let x = 0 ++x
— , .
let x = 0 x++
(--)
--
++
,
1
, .
let x = 0 x--
(-)
.
let x = 2 -x
(+)
, , . — .
let x = 2 +x
▍
JavaScript, (
=
), , . , ,
+=
.
let x = 2 x += 3 x
: « , , , , ». , .
let x = 2 x = x + 3 x
:
▍
. , .
const a = 1 * 2 + 5 / 2 % 2
2.5
. , . , .
- + ++ --
— ,/ %
— , ,+ -
—= += -= *= /= %= **=
—
, , . , .
const a = 1 * 2 + 5 / 2 % 2 const a = 2 + 2.5 % 2 const a = 2 + 0.5 const a = 2.5
. .
const a = 1 * (2 + 5) / 2 % 2
1.5
.
▍ Math
Math
, .
. , .
, ,
Math.E
— , e,
Math.PI
— , π.
Math.E
.
Math.abs()
—Math.ceil()
— , ,Math.cos()
— ,Math.floor()
— , ,Math.max()
—Math.min()
—Math.random()
— [0, 1) ( 1)Math.round()
—Math.sqrt()
—
▍
JavaScript , .
, . , , , .
.
<
— «»>
— «».<=
— « ».>=
— « ».
, .
1 === true
, ,
1
true
.
1
true
,
1
true
.
, , . Node.js. , :
PDF- Node.js.
Sumário
, this, , , . , ES6.
Caros leitores! , JavaScript?
