Olá pessoal! No final de setembro, um novo fluxo do curso
"Fullstack JavaScript Developer" começará no
OTUS . Antecipando o início das aulas, queremos compartilhar com você um artigo de autor preparado especialmente para os alunos do curso.
Autor do artigo: Pavel Yakupov
Pré-visualização Quero observar imediatamente que, neste artigo, os tópicos familiares aos “ninjas” são examinados, e o artigo tem como objetivo fazer com que os iniciantes compreendam melhor algumas das nuances do idioma e não se percam nas tarefas que costumam ser dadas durante a entrevista - afinal, tais As tarefas não têm nada a ver com desenvolvimento real, e quem as fornece, na maioria das vezes dessa maneira, tenta entender o quanto você conhece JavaScript.

Tipos de memória de referência
Como exatamente os dados são armazenados em JavaScript? Muitos cursos de programação começam a explicar com o clássico: uma variável é um tipo de “caixa” na qual armazenamos alguns dados. Quais, ao que parece, parece que não importa para idiomas com digitação dinâmica: o intérprete "engolirá" quaisquer tipos de dados e alterará dinamicamente o tipo, se necessário, e você não deve pensar nos tipos de variáveis e como eles são processados. O que está errado, é claro, e, portanto, iniciaremos a discussão de hoje com recursos que geralmente desaparecem: como as variáveis são armazenadas em JavaScript - na forma de primitivas (cópias) ou na forma de links.
Listaremos imediatamente os tipos de variáveis que podem ser armazenadas na forma de primitivas: são
boolean
,
null
,
undefined
,
Number
,
String
,
Symbol
,
BigInt
. Quando encontramos variáveis declaradas separadamente com esse tipo de dados, devemos lembrar que durante a inicialização eles criam uma célula de memória - e que podem ser atribuídos, copiados, transferidos e retornados por valor.
O restante do JavaScript depende de áreas de memória referenciadas. Por que eles são necessários? Os criadores da linguagem tentaram criar uma linguagem na qual a memória fosse usada da maneira mais econômica possível (e isso não era novidade na época). Para ilustrar, imagine que você precise se lembrar dos nomes de três novos colegas de trabalho - nomes completamente novos e, para melhorar a comparação, seus novos colegas da Índia ou da China com nomes incomuns para você. Agora imagine que seus colegas são chamados assim como você e seus dois melhores amigos na escola. Em que situação será mais fácil lembrar? Aqui, a memória de uma pessoa e um computador funciona da mesma forma. Aqui estão alguns exemplos específicos:
let x = 15;
Portanto, se você encontrar uma tarefa semelhante em uma entrevista, tente entender imediatamente que tipo de dados está à sua frente - de onde eles vieram e como obtiveram o valor, como um tipo primitivo ou como referência.

Trabalho de contexto
Para entender exatamente como o contexto funciona em JS, você precisa estudar alguns pontos:
- Nível global / local de visibilidade.
- A diferença de contexto ao inicializar variáveis no escopo global / local.
- Funções de seta.
Era uma vez, no ES5, tudo muito simples: havia apenas uma declaração de variável usando var, que quando declarada no fluxo do programa era considerada global (o que significava que a variável é atribuída como uma propriedade a um objeto global, como
window
ou
global
). Então
let
e
const
chegaram à cena, que se comportam de maneira um pouco diferente: eles não são atribuídos ao objeto global e são armazenados na memória de maneira diferente, focando no escopo do bloco. Agora, o var já é considerado obsoleto, porque seu uso pode levar ao entupimento do escopo global e, além disso,
let
parecer muito mais previsível.
1. Portanto, para entender, vale a pena entender claramente qual é o escopo do JavaScript (escopo). Se uma variável é declarada no escopo global usando a diretiva
let
, ela não é atribuída ao objeto de
window
, mas é salva globalmente.
Vamos seguir para as tarefas que os iniciantes mais frequentemente fazem nas perguntas contextuais da entrevista.
//: ? let x = 15; function foo(){ let x = 13; return x; } console.log(x)// 15 foo(); console.log(x)// x = foo(); console.log(x)// return ,
2. Ao mesmo tempo, nem todos os iniciantes sabem como o interpretador JavaScript lê o código: na verdade, ele lê duas vezes, na primeira vez que lê o código de funções declaradas como Declaração de Função (e está pronto para executá-las na segunda leitura e execução reais) ) Outro pequeno truque está relacionado a
var
e
let
: na primeira vez que uma variável com a diretiva
var
é lida, ela é definida como
undefined
. Mas com
let
sua chamada prematura não é possível:
console.log(x); console.log(y) var x = 42; let y = 38;
3. As funções de seta que apareceram no ES6 rapidamente ganharam popularidade - foram rapidamente adotadas pelos programadores no
Node.js. (devido a uma rápida atualização do mecanismo) e no
React (devido aos recursos da biblioteca e ao inevitável uso do Babel). Com relação ao contexto, as funções de seta seguem a seguinte regra: elas não se vinculam a
this
. Ilustramos isso:
var x = 4; var y = 4; function mult(){ return this.x * this.y; } let foo = mult.bind(this); console.log(foo()); let muliply = ()=>x*y; console.log(muliply()); /* x y let, function declaration */

Tipos de dados e a que se aplica
Digamos imediatamente: uma matriz é essencialmente um objeto e, em JavaScript, essa não é a primeira variação de um objeto - Mapa, WeakSet, Set e coleções confirmam isso.
Portanto, uma matriz é um objeto, e sua diferença em relação a um objeto regular em JS é, em primeiro lugar, uma velocidade de trabalho mais alta devido à otimização da indexação e, em segundo lugar, herança do Array.prototype, que fornece um conjunto maior de métodos, e é por isso que Big Brother »
Object.prototype
.
console.log(typeof({})) console.log(typeof([])) console.log(typeof(new Set)) console.log(typeof(new Map)) //
O próximo na fila de esquisitices nos tipos de dados é
null
. Se você perguntar ao JavaScript que tipo de dados é nulo, obteremos uma resposta bastante inequívoca. No entanto, aqui não vai ficar sem alguns truques:
let x = null; console.log(typeof(x)); //! , null objet, ? console.log(x instanceof Object.prototype.constructor); //false // ! )
Vale lembrar que
null
é um tipo de dados especial - embora o início do exemplo anterior aponte estritamente para outro. Para uma melhor compreensão de por que esse tipo específico foi adicionado à linguagem, parece-me que vale a pena explorar os conceitos básicos da sintaxe C ++ ou C #.
E, é claro, nas entrevistas muitas vezes se depara com essa tarefa, cuja peculiaridade está relacionada à tipagem dinâmica:
console.log(null==undefined);//true console.log(null===undefined);// false
Um grande número de truques está associado à conversão de tipos ao comparar em JS; não podemos fisicamente trazer todos eles aqui. Recomendamos referir-se a
"Que diabos JavaScript" .

Recursos ilógicos deixados no idioma durante o processo de desenvolvimento
Adição de linhas. De fato, a adição de strings com números não pode ser atribuída a erros no desenvolvimento da linguagem, mas no contexto do JavaScript isso levou a exemplos bem conhecidos que são considerados não lógicos o suficiente:
codepen.io/pen/?editors=0011 let x = 15; let y = "15"; console.log(x+y);// "" console.log(xy); //
O fato de o plus simplesmente adicionar linhas com números é relativamente ilógico, mas você só precisa se lembrar disso. Isso pode ser especialmente incomum, porque as outras duas linguagens interpretadas populares e amplamente usadas no desenvolvimento web - PHP e Python - não lançam esses truques com adição de strings e números e se comportam de maneira muito mais previsível em tais operações.
Exemplos semelhantes são menos conhecidos, por exemplo, com NaN:
console.log(NaN == NaN); //false console.log(NaN > NaN); //false console.log(NaN < NaN); //false … ... , NaN? console.log(typeof(NaN)); // number
Geralmente, o NaN traz surpresas desagradáveis se, por exemplo, você configurou incorretamente a verificação de tipo.
O exemplo com 0.1 +0.2 é muito mais famoso - porque esse erro está relacionado ao formato IEEE 754, que também é usado, por exemplo, em um Python "matemático".
Também incluímos um bug menos conhecido com o número Epsilon, cuja razão está na mesma linha:
console.log(0.1+0.2)// 0.30000000000000004 console.log(Number.EPSILON);// 2.220446049250313e-16 console.log(Number.EPSILON + 2.1) // 2.1000000000000005
E perguntas um pouco mais complicadas:
Object.prototype.toString.call([])// ? // -> '[object Array]' Object.prototype.toString.call(new Date) // Date? // -> '[object Date]'

Etapas de processamento de eventos
Muitos iniciantes não entendem os eventos do navegador. Muitas vezes, mesmo desconhecidos, são os princípios mais básicos pelos quais os eventos do navegador funcionam - interceptação, subida e eventos padrão. A coisa mais misteriosa do ponto de vista de um iniciante é o surgimento de um evento que, sem dúvida, é justificado no início, levanta questões. O pop-up funciona da seguinte maneira: quando você clica em um elemento DOM aninhado, o evento é acionado não apenas nele, mas também no pai, se um manipulador com esse evento também foi instalado no pai.
No caso de surgir um evento, talvez seja necessário cancelá-lo.
// , function MouseOn(e){ this.style.color = "red"; e.stopPropagation(); // }
Além disso, para iniciantes, geralmente é um problema cancelar eventos que ocorrem por padrão. Isso é especialmente importante no desenvolvimento de formulários - porque a validação de formulários, por exemplo, precisa ser feita no lado do cliente e no servidor:
codepen.io/isakura313/pen/GRKMdaR?editors=0010 document.querySelector(".button-form").addEventListener( 'click', function(e){ e.preventDefault(); console.log(' . , ') } )
O cancelamento da superfície de um evento também pode trazer alguns problemas: por exemplo, você pode criar a chamada "zona morta" na qual o necessário não funcionará - por exemplo, um evento de um elemento que "não tem sorte" por estar próximo.
Obrigado a todos pela atenção! Aqui estão alguns links úteis, dos quais você pode obter muitas informações úteis:
Só isso. Estamos esperando por você no
seminário on-line gratuito , que será realizado em 12 de setembro.