Tentamos fazer algo interessante e incomum para você. Eu realmente espero que tenhamos sucesso. Não queríamos deixar você sem resposta e sem explicação. Vamos acertar.
Para começar, quero lembrá-lo de como a competição foi realizada. Foram quatro rodadas de 15 perguntas sobre JS, uma rodada fora de competição de 15 perguntas sobre o React e uma final de 10 perguntas.

Sob o corte - a análise das tarefas das 4 primeiras rodadas.
Esta é a segunda parte de nossa análise.
Reaja às perguntas aqui
Como todos nós fizemos isso? Decidimos que precisamos gerar cerca de 80 a 90 perguntas para que haja um estoque para escolher. Depois disso, dividimos tudo em tópicos:
- eventos do navegador
- várias APIs (matriz, conjunto, define propriedade, etc.),
- atenção
- trabalhar com números fracionários
- elevação
- laço de evento
- conversão de tipo
- typeof
- lógico (com lógico AND e OR)
Depois disso, as perguntas foram distribuídas em quatro rodadas. Tentamos tornar todos os passeios iguais em complexidade, por isso fizemos várias visitas passando nesses testes e determinando onde as perguntas são mais fáceis, onde é mais difícil e substituímos as questões pendentes por outras mais adequadas. E fizemos o mesmo número de perguntas sobre um tópico específico em cada rodada. Como resultado, verificou-se que em diferentes turnês havia perguntas semelhantes, mas não as mesmas.
Por causa disso, não parece muito conveniente classificar os passeios, porque haverá muitas explicações duplicadas, sugiro analisá-las por tópico. Vamos começar com o mais simples.
Perguntas para atenção:
O que será exibido no console?
console.log(0,1 + 0,2); a) 0.30000000000000004 b) 0.3 c) 2 d) 0 1 2
Resposta + análised) 0 1 2
Aqui fica entre os números, e não .
se você formatar a pergunta assim:
console.log(0, 1 + 0, 2);
tudo ficará claro
O que será exibido no console?
(() => { 'use strict'; a = null + undefined; console.log(a); })(); a) 0 b) NaN c) null d)
Resposta + análised) erro
a
não é criado como uma variável (não é uma declaração de variável), aqui há uma expressão de atribuição implícita para this.a
que muitas vezes pode não ser o que você espera, porque uma variável global window.a
será criada no modo estrito, isso é proibido.
O que será exibido no console?
let foo = function bar() { return 123; }; console.log( typeof bar() ); a) 'function' b) 'number' c) 'undefined' d)
Resposta + análised) erro
Esta é uma expressão funcional (expressão) - o nome da função nesse caso é local para a função. Para chamar uma função, você precisa chamar foo
, não bar
. Se fosse uma declaração, a resposta seria number
.
Perguntas sobre como trabalhar com números fracionários:
O que será exibido no console?
console.log(0.1 ** 2); a) 0.2 b) 0.01 c) 0.010000000000000002 d) NaN
O que será exibido no console?
console.log(0.1 + 0.2); a) 0.30000000000000004 b) 0.3 c) 2 d) NaN
Resposta + análisea) 0.30000000000000004
**
- este é um análogo do Math.pow ao quadrado 0.1
- deve sair 0.01
, mas em JS (como em muitos outros idiomas) há um problema conhecido com a precisão das operações ao trabalhar com números de ponto flutuante . Será 0.010000000000000002
Isso se deve ao fato de que no sistema binário uma fração infinita é obtida, porque exatamente 64 bits são sempre alocados para um número em JS - todos os números são sempre ponto flutuante de precisão dupla. O mesmo acontece quando adicionado.
Passamos às perguntas um pouco mais complicadas.
Eventos no navegador:
Existe um manipulador de eventos no elemento .. Quais valores dentro desse manipulador sempre serão os mesmos?
elem.onclick = function(event) { } a) event.target event.currentTarget b) event.target this c) event.currentTarget this d)
Resposta + análisec) event.currentTarget e isso
this
- sempre apontará para um elemento
currentTarget
- o elemento no qual o evento trava
target
- o elemento no qual o evento ocorreu
O que esse código produzirá ao clicar em uma div?
div.onclick = function() { console.log(1) }; div.onclick = function() { console.log(2) }; div.addEventListener('click', function() { console.log(3) }); a) 1 b) 1 3 c) 2 3 d) 3
Resposta + análisec) 2 3
O onclick adicionará o manipulador console.log(1)
, mas na próxima linha nós o trituraremos com uma nova função e apenas o console.log(2)
permanecerá. onclick
é uma propriedade DOM; é sempre uma
Os eventos funcionarão na ordem em que estão suspensos; primeiro 2 e 3 serão exibidos.
Se addEventListener
várias vezes, cada um deles funcionaria, porque manipuladores adicionam eventos à fila.
Seção de perguntas sobre várias APIs
defineProperty:
O que esse código produzirá?
(() => { const obj = { key: 1 }; Object.defineProperty(obj, 'key', { enumerable: false, configurable: false, writable: false, value: 2 }); console.log(obj.key); obj.key = 3; console.log(obj.key); })(); a) 1, 2 b) 2, 2 c) 2, 3 d)
O que esse código produzirá?
(() => { 'use strict'; const obj = { key: 1 }; Object.defineProperty(obj, 'key', { enumerable: false, configurable: false, writable: false, value: 2 }); console.log(obj.key); obj.key = 3; console.log(obj.key); })(); a) 1, 2 b) 2, 2 c) 2, 3 d) 2,
O que esse código produzirá?
(() => { const obj = { key: 1 }; Object.defineProperty(obj, 'key', { enumerable: false, configurable: false, writable: true, value: 2 }); console.log(obj.key); obj.key = 3; console.log(obj.key); })(); a) 1, 2 b) 2, 2 c) 2, 3 d)
Resposta + análisec) 2, 3
Em todas as perguntas acima, o conhecimento do método defineProperty
é defineProperty
e defineProperty
mais especificamente, configurações writable
. Se estiver definido como false
é proibido alterar os valores da chave transmitida pelo segundo parâmetro em defineProperty
. A única diferença é que, sem o modo estrito - use strict
mecanismo fingirá que está tudo bem, mas não alterará o valor, e haverá um erro no modo estrito.
incremento:
O que esse código produzirá?
let x = 5; console.log(x++); a) 5 b) 6 c) '5++' d)
O que esse código produzirá?
const a = 5; console.log(a++); a) 5 b) 6 c) '5++' d)
A respostad) erro
Ao usar o formulário de incriminação postfix, o valor é retornado antes do aumento.
E com prefixo depois, ou seja, console.log(++5)
imprimiria 6
const
não pode ser substituído; Number é um primitivo, quando incrementado, a variável será substituída pelo novo valor e ocorrerá um erro.
Conjunto:
O que esse código produzirá?
const a = [...new Set([1, 1, 2, , 3, , 4, 5, 5])]; console.log(a); a) [1, 1, 2, , 3, , 4, 5, 5] b) [1, 2, undefined, 3, 4, 5] c) [1, 1, 2, undefined, 3, undefined, 4, 5, 5] d)
A respostab) [1, 2, indefinido, 3, 4, 5]
O que esse código produzirá?
let set = new Set([10, '10', new Number(10), 1e1, 0xA]); console.log(set.size); a) 5 b) 3 c) 2 d) 1
O que esse código produzirá?
let obj = {}; let set = new Set([obj, obj, {}, {}, {...{}}, {...obj}]); console.log(set.size); a) 6 b) 5 c) 2 d) 1
A respostab) 5
Set
é um conjunto; por definição, não pode haver valores idênticos. A questão é como esses valores são comparados. Primitivas são comparadas por valor e objetos por referência.
Ele próprio não cita tipos de dados e pode armazenar valores de qualquer tipo 1e1
e 0xA
- será convertido em um sistema decimal e obter 10
.
E novos objetos nem sempre são iguais: console.log({} == {})
retornará false
pois os objetos serão criados de uma nova maneira em diferentes locais da memória e seus links não serão iguais.
O que esse código produzirá?
console.log(Infinity / Infinity); a) NaN b) 1 c) Error d) Infinity
A respostaa) NaN
É impossível dividir o infinito em infinito e subtrair o infinito do infinito, pois do ponto de vista matemático, obtém-se incerteza, o mesmo acontecerá quando o Infinity
multiplicado e 0
erros não causarem operações matemáticas - haverá NaN
Perguntas sobre Spread:
O que esse código produzirá?
const a = { ...{ a: 1, b: 2, c: 3 }, ...{ a: 2, c: 4, d: 8 } }; console.log(a); a) { a: 2, b: 2, c: 4, d: 8 } c) { a: 1, b: 2, c: 3, d: 8 } c) { a: 1, b: 2, c: 3, a: 2, c: 4, d: 8 } d)
A respostaa) {a: 2, b: 2, c: 4, d: 8}
O que esse código produzirá?
const a = [...[1, 2], ...[[3, 4]], ...[5, 6]]; console.log(a); a) [1, 2, 3, 4, 5, 6] b) [1, 2, [3, 4], 5, 6] c) [[1, 2], [[3, 4]], 5, 6] e)
Resposta + análiseb) [1, 2, [3, 4], 5, 6]
Spread
operador Spread
serve para analisar um objeto ou matriz em partes. Ele pega valores da entidade depois de ...
e os copia para o criado. Vale a pena notar que, para uma matriz e um objeto, ele abre para 1 nível, ou seja ...[[1]]
retornará uma matriz com um elemento, não o próprio elemento. Não pode haver valores duplicados nos objetos; portanto, os valores divulgados após serão substituídos pelos que foram divulgados anteriormente. Isso pode ser usado para especificar configurações padrão.
const fn = (actualProps) => ({ ...defaultProps, ...actualProps })
Todos os valores padrão serão substituídos pelos valores passados, se houver.
O que esse código produzirá?
console.log(parseInt(' -10,3 ')); a) -10,3 b) -10 c) TypeError d) NaN
Resposta + análiseb) -10
Descrição exaustiva com MDN :
Se a função parseInt encontrar um caractere que não seja um número no sistema numérico especificado, ela pulará esse e todos os caracteres subseqüentes (mesmo que sejam adequados) e retornará um número inteiro convertido da parte da sequência que antecede esse caractere. parseInt corta a parte fracionária de um número. Espaços no início e no final de uma linha são permitidos.
O que esse código produzirá?
const t = { a: 6, b: 7 }; const p = new Proxy(t, { get() { return 12; }, }); console.log(pa); pa = 18; console.log(pa); console.log(ta); a) b) 12 18 18 c) 12 18 6 d) 12 12 18 e) 6 18 6
Resposta + análised) 12 12 18
Proxy
intercepta todas as chamadas para o objeto. Nesse caso, procuramos apenas o método get
e sempre retornamos 12
independentemente do campo do objeto que estamos acessando. Nesse caso, não tocamos em set e, ao acessar o proxy, o valor no objeto será substituído.
matrizes:
O que esse código produzirá?
let arr = []; arr[1] = 1; arr[5] = 10; console.log(arr.length); a) 1 b) 5 c) 6 d) 10
O que esse código produzirá?
let arr = new Array(3); console.log(arr[1]); a) undefined b) 1 c) 3 d)
Resposta + análisea) indefinido
Quando criamos uma Array
com um argumento numérico, isso significa o comprimento da matriz. Uma matriz é criada vazia, todos os valores são undefined
. O mesmo acontece se você criar acesso a um campo de matriz inexistente. Vale a pena notar que, se você passar um número para Array
, uma matriz com esse elemento será retornada, ou seja, Array('a')
retornará ['a']
operações lógicas &&
, ||
, ==
, etc .:
O que esse código produzirá?
console.log([] && 'foo' && undefined && true && false); a) [] b) 'foo' c) undefined d) true
O que esse código produzirá?
console.log(0 || 1 && 2 || 3); a) 0 b) 1 c) 2 d) 3
O que esse código produzirá?
console.log(0 || '' || 2 || undefined || true || false); a) 0 b) false c) 2 d) true
O que esse código produzirá?
console.log(2 && '1' && null && undefined && true && false); a) 2 b) false c) undefined d) null
O que esse código produzirá?
console.log([] && {} || null && 100 || ''); a) true b) 100 c) '' d) {}
Resposta + análised) {}
Uma matriz vazia []
é true
como um objeto vazio {}
.
A cadeia vazia ''
, null
e undefined
é false
Lógico ou ||
- retorna o operando esquerdo, se verdadeiro, caso contrário, retorna o operando direito.
Lógico e &&
- retorna o operando esquerdo, se for falso, caso contrário, retorna o operando direito.
Às vezes, isso pode ser encontrado no código, antes do aparecimento dos parâmetros padrão, eles costumavam escrever assim - se não houver parâmetros na função, usamos os parâmetros padrão:
function f(userParams) { var params = userParams || defaultParams; }
Agora o React geralmente verifica se a condição é verdadeira, e renderizamos algo:
{ isDivVisible && <div>bla-bla</div> }
comparação de matriz:
O que esse código produzirá?
const arrayFoo = [1, 2, 3, 4]; const arrayBaz = [1, 2, 3, 4]; console.log(arrayFoo == arrayBaz && arrayFoo == arrayBaz); a) false b) true c) undefined d)
O que esse código produzirá?
console.log([null, 0, -0].map(x => 0 <= x)); a) [false, true, false] b) [false, true, true] c) [false, false, false] d) [true, true, true]
A respostad) [verdadeiro, verdadeiro, verdadeiro]
O que esse código produzirá?
const arrayFoo = [1, 2, 3, 4]; const arrayBaz = [1, 2, 3, 4]; console.log(arrayFoo >= arrayBaz && arrayFoo <= arrayBaz); a) true b) false c) undefined d)
O que esse código produzirá?
const foo = [1, 2, 3, 4]; const baz = '1,2,3,4'; console.log(foo >= baz && foo <= baz); a) false b) true c) undefined d)
Resposta + análiseb) verdadeiro
Quando ==
comparar por referência.
durante a operação >, >=, <, <=
operandos são convertidos em primitivas e o método valueOf é chamado no arrayFoo
, que deve retornar o valor primitivo arrayFoo
, mas retorna uma referência à mesma matriz. Em seguida, uma conversão para um valor primitivo ocorre chamando o método toString
, que, por sua vez, retornará uma representação de string da matriz na forma de "1,2,3,4", compara as duas matrizes lexicograficamente e retorna true
O que esse código produzirá?
console.log(+0 == -0); console.log(+0 === -0); console.log(Object.is(+0, -0)); a) true, false, false b) true, true, false c) false, true, true d) false, false. false
Resposta + análiseb) verdadeiro, verdadeiro, falso
Explicação abrangente com MDN :
O comportamento desse método (falando sobre Object.is
) não é o mesmo que o operador ===
. O operador ===
(assim como o operador ==
) considera os valores numéricos -0
e +0
iguais e o valor Number.NaN
não Number.NaN
igual a si próprio.
Perguntas sobre içamento:
O que esse código produzirá?
console.log(str); const str = 'HeadHunter'; a) 'HeadHunter' b) undefined c)
O que esse código produzirá?
var arrayFunction = []; for (let i = 0; i <= 10; i++) { arrayFunction.push(() => i); } console.log(arrayFunction[3]()); a) 4 b) 0 c) 11 d) 3
O que esse código produzirá?
console.log(str); var str = 'HeadHunter'; a) 'HeadHunter' b) undefined c) null c)
O que esse código produzirá?
console.log(foo); var foo; foo = foo ? 1 : 0; console.log(foo); a) b) undefined 0 c) '' 1 d) 0 0
Uma chamada de função funcionará?
getCompanyName(); function getCompanyName() { return 'HeadHunter'; } a) b) , . c)
O que esse código produzirá?
var arrayFunction = []; for (var i = 0; i <= 10; i++) { arrayFunction.push(() => i); } console.log(arrayFunction[3]()); a) 4 b) 0 c) 11 d) 3
Resposta + análisec) 11
As declarações de função são exibidas, mas nenhuma expressão.
var
aparece, mas até a inicialização não ser undefined
.
let
e const
não aparecem e têm escopo em um bloco, ou seja, limitado a {}
.
Para que o loop funcione corretamente com var
você precisa usar um fechamento, o valor será salvo nele.
(Essa costumava ser uma tarefa clássica para entrevistas, mas agora deixamos)
var arrayFunction = []; for (var i = 0; i <= 10; i++) { (function(i) { arrayFunction.push(() => i); })(i); } console.log(arrayFunction[3]());
O que esse código produzirá?
console.log(true + false); a) true b) false c) 1 d) 0
Resposta + análisec) 1
Nenhum dos operadores é uma sequência, +
leva a um número. Acontece 1 + 0
O que esse código produzirá?
console.log([] - 100 + ![]); a) false b) '-100' c) -100 d) NaN
Resposta + análisec) -100
A matriz é convertida em uma string; depois disso, por causa de -
convertemos em um número, resulta em -100
, depois convertemos a matriz em false
, e este é 0
O que esse código produzirá?
console.log([[], []] + 1); a) 1 b) '1' c) ',1' d) NaN
Resposta + análisec) ', 1'
toString
no objeto, enquanto toString
também será chamado em todos os elementos da matriz. [].toString
retornará uma string vazia ''
. Acontece que , + 1
- a resposta ,1
.
O que esse código produzirá?
console.log([] + 100 + 5); a) 105 b) '1005' c) 1005 d) NaN
Resposta + análiseb) '1005'
A matriz é redutível a uma sequência e, em seguida, a concatenação já ocorre.
O que esse código produzirá?
console.log(1 + { a: 3 } + '2'); a) 6 b) '1[object Object]2' c) 3 d) NaN
Resposta + análiseb) '1 [objeto Objeto] 2'
Converta em uma string - é apenas concatenação.
O que esse código produzirá?
console.log(10.toString() + 10 + 0x1); a) '10101' b) 21 c) '10100x1' d)
Resposta + análised) erro
Para um número, um ponto .
significa o início da parte fracionária, esperamos um número lá - haverá um erro.
Para que este exemplo funcione bem, você precisa escrever 10..toString()
O que esse código produzirá?
console.log(5 + false - null + true); a) '0true' b) NaN c) 6 d)
Resposta + análisec) 6
Aqui tudo é reduzido a um número, verifica-se 5 + 0 - 0 + 1
O que esse código produzirá?
console.log(true + NaN + false); a) true b) NaN c) false d) 1
Resposta + análiseb) NaN
Reduzimos tudo para um número, ao adicionar números com NaN
- obtemos NaN
O que esse código produzirá?
console.log('0x1' + '1' - '1e1'); a) 17 b) 7 c) '0x111e1' d) NaN
Resposta + análiseb) 7
Já existem linhas após a primeira concatenação, obtemos: '0x11' - '1e1'
. Por causa do sinal -
trazemos tudo para um número.
0x11
- O número hexadecimal em decimal é 17
.
1e1
- a forma exponencial é igual a 1 * 10 ** 1
- ou seja, apenas 10
.
typeof:
O que esse código produzirá?
let foo = () => { return null; }; console.log( typeof typeof foo ); a) 'function' b) 'string' c) 'null' d)
O que esse código produzirá?
typeof function() {}.prototype; a) 'function' b) 'object' c) 'undefined' d)
Resposta + análiseb) 'objeto'
typeof
sempre retorna uma string, tem uma prioridade mais baixa do que chamar a função; portanto, a função é executada primeiro e typeof
é aplicado ao resultado retornado a ela. Objetos de função herdam de Function.prototype. Speck determina claramente que este é um objeto.
loop de evento:
Vamos começar com 2 perguntas sobre promessas.
O que esse código produzirá?
Promise.reject() .then(() => console.log(1), () => console.log(2)) .then(() => console.log(3), () => console.log(4)); a) 1 4 b) 1 3 c) 2 3 d) 2 4
O que esse código produzirá?
Promise.reject('foo') .then(() => Promise.resolve('bar'), () => {}) .then((a) => {console.log(a)}) a) foo b) bar c) undefined d)
Resposta + análisec) indefinido
Promise.reject
- retorna uma promessa em um estado rejeitado.
Deve-se lembrar que then
em then
necessários 2 parâmetros, onReject
chamada onReject
e onReject
. Se ocorrer um erro antes disso, obteremos o retorno de chamada onReject
. Se não houver nenhum erro, então entraremos em onFulfill
. E não esqueça que () => {}
retorna não um objeto vazio, mas undefined
, para retornar um objeto vazio, você precisa escrever assim: () => ({})
a ordem das tarefas.
O que esse código produzirá?
async function get1() { return 1; } function get2() { return 2; } (async () => { console.log(await get1()); })(); console.log(get2()); a) 1,2 b) 2,1 c) 1 d) 2
O que esse código produzirá?
setTimeout(() => {console.log('in timeout')}); Promise.resolve() .then(() => {console.log('in promise')}); console.log('after'); a) in timeout, in promise, after b) after, in promise, in timeout c) after, in timeout, in promise d) in timeout, after, in promise
A respostab) depois, em promessa, em timeout
O que esse código produzirá?
let __promise = new Promise((res, rej) => { setTimeout(res, 1000); }); async function test(i) { await __promise; console.log(i); } test(1); test(2); a) 1, 2 b) 2, 1 c) 1 d) 2
O que esse código produzirá?
console.log('FUS'); setTimeout(() => {console.log('RO')}) Promise.resolve('DAH!').then(x => console.log(x)); a FUS RO DAH! b) FUS DAH! RO c) RO FUS DAH! d) DAH! RO FUS
O que esse código produzirá?
console.log(1); setTimeout(() => console.log('setTimeout'), 0); console.log(2); Promise.resolve().then(() => console.log('promise1 resolved')); console.log(3); a) 1, 2, 3, 'setTimeout', 'promise1 resolved' b) 1, 'setTimeout', 2, 'promise1 resolved', 3 c) 1, 2, 3, 'promise1 resolved', 'setTimeout' d) 1, 2, 'promise1 resolved', 3, 'setTimeout'
Resposta + análisec) 1, 2, 3, 'promessa1 resolvida', 'setTimeout'
Primeiro, todas as chamadas síncronas são acionadas; depois, quando a pilha de chamadas está vazia, é chamado o que está na fila (tarefas assíncronas). Primeiro, microtask - promessas e mutation observer
. No final da tarefa atual, todas as microtask são executadas. Em conexão com essa microtask, você pode bloquear o loop de eventos; após a conclusão da tarefa, o navegador é processado. Depois disso, as tarefas de macro - os intervalos são executados.
Este é um exemplo muito simplificado, em mais detalhes eu aconselho você a ver o discurso de Mikhail Bashurov
E a última pergunta promessa vs aguarda
O que esse código produzirá?
const p = Promise.resolve(); (async () => { await p; console.log('1'); })(); p.then(() => console.log('2')) .then(() => console.log('3'));
a) 1 2 3
b) 2 1 3
c) 2 3 1
d) 3 2 1
Resposta + análisec) 2 3 1
De acordo com as especificações, as promessas adicionadas até then
devem primeiro ser executadas e somente depois disso você precisa continuar
execução de uma função assíncrona. Speck . Para uma compreensão mais detalhada sobre por que isso ocorre, aconselho a ler um excelente artigo na v8.dev