Intentamos hacer algo interesante e inusual para usted. Realmente espero que tengamos éxito. No queríamos dejarlo sin respuesta y sin explicación por qué. Vamos a hacerlo bien.
Para comenzar, quiero recordarles cómo se llevó a cabo la competencia, hubo 4 rondas de 15 preguntas sobre JS, 1 ronda no competitiva de 15 preguntas sobre React y una final de 10 preguntas.

Bajo el corte: el análisis de las tareas de las primeras 4 rondas.
Esta es la segunda parte de nuestro análisis.
Reaccionar preguntas aquí
¿Cómo hicimos esto todos? Decidimos que necesitamos generar alrededor de 80-90 preguntas para que haya un stock para elegir. Después de eso, dividimos todo en temas:
- eventos del navegador
- varias API (Array, Set, defineProperty, etc.),
- atención
- trabajar con números fraccionarios
- levantamiento
- bucle de eventos
- conversión de tipo
- tipo de
- lógico (con lógico AND y OR)
Después de eso, las preguntas se distribuyeron en 4 rondas. Intentamos hacer que todos los recorridos sean iguales en complejidad, para esto realizamos varias visitas pasando estos exámenes y determinando dónde son más fáciles las preguntas, dónde es más difícil y reemplazamos las preguntas pendientes por otras más adecuadas. E hicimos aproximadamente la misma cantidad de preguntas sobre un tema en particular en cada ronda. Como resultado, resultó que en diferentes recorridos había preguntas similares, pero no las mismas.
Debido a esto, no parece muy conveniente clasificar los recorridos porque habrá muchas explicaciones duplicadas, sugiero mirarlas por tema. Comencemos con lo más simple.
Preguntas para atención:
¿Qué se mostrará en la consola?
console.log(0,1 + 0,2); a) 0.30000000000000004 b) 0.3 c) 2 d) 0 1 2
Respuesta + análisisd) 0 1 2
Aquí se encuentra entre los números, y no .
si formatea la pregunta de esta manera:
console.log(0, 1 + 0, 2);
todo se aclarará
¿Qué se mostrará en la consola?
(() => { 'use strict'; a = null + undefined; console.log(a); })(); a) 0 b) NaN c) null d)
Respuesta + análisisd) error
a
no se crea como una variable (no una Declaración de variable), aquí hay una Expresión de asignación implícita para this.a
que a menudo puede no ser lo que espera, porque window.a
creará una window.a
variable global window.a
a en modo estricto, esto está prohibido.
¿Qué se mostrará en la consola?
let foo = function bar() { return 123; }; console.log( typeof bar() ); a) 'function' b) 'number' c) 'undefined' d)
Respuesta + análisisd) error
Esta es una expresión funcional (expresión): el nombre de la función en este caso es local para la función. Para llamar a una función, debe llamar a foo
, no bar
. Si fuera una declaración, la respuesta sería number
.
Preguntas sobre cómo trabajar con números fraccionarios:
¿Qué se mostrará en la consola?
console.log(0.1 ** 2); a) 0.2 b) 0.01 c) 0.010000000000000002 d) NaN
¿Qué se mostrará en la consola?
console.log(0.1 + 0.2); a) 0.30000000000000004 b) 0.3 c) 2 d) NaN
Respuesta + análisisa) 0.30000000000000004
**
- este es un análogo de Math.pow al cuadrado 0.1
- debería resultar 0.01
, pero en JS (como en muchos otros idiomas) hay un problema conocido con la precisión de las operaciones cuando se trabaja con números de coma flotante . Será 0.010000000000000002
Esto se debe al hecho de que en el sistema binario se obtiene una fracción infinita, porque exactamente 64 bits siempre se asignan para un número en JS: todos los números son siempre de coma flotante de doble precisión. Lo mismo sucede cuando se agrega.
Pasamos a las preguntas un poco más complicadas.
Eventos en el navegador:
Hay un controlador de eventos en el elemento. ¿Qué valores dentro de este controlador siempre serán los mismos?
elem.onclick = function(event) { } a) event.target event.currentTarget b) event.target this c) event.currentTarget this d)
Respuesta + análisisc) event.currentTarget y esto
this
siempre apuntará a un elemento
currentTarget
: el elemento en el que se cuelga el evento
target
- el elemento en el cual ocurrió el evento
¿Qué generará este código al hacer clic en un 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
Respuesta + análisisc) 2 3
onclick agregará el controlador console.log(1)
, pero en la siguiente línea lo procesaremos con una nueva función y solo console.log(2)
. onclick
es una propiedad DOM; siempre es una
Los eventos funcionarán en el orden en que se cuelgan, primero se mostrarán 2 y luego 3.
Si addEventListener
varias veces, entonces cada uno de ellos funcionaría, porque los controladores agregan eventos a la cola.
Sección de preguntas sobre varias API
defineProperty:
¿Qué generará este código?
(() => { 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)
¿Qué generará este código?
(() => { '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,
¿Qué generará este código?
(() => { 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)
Respuesta + análisisc) 2, 3
En todas las preguntas anteriores, se defineProperty
conocimiento del método defineProperty
y defineProperty
más específicamente, la configuración de writable
. Si se establece en false
está prohibido cambiar los valores de la clave que se pasa como el segundo parámetro para defineProperty
. La única diferencia es que sin el modo estricto: use strict
motor fingirá que todo está bien, pero no cambiará el valor y habrá un error en el modo estricto.
incremento:
¿Qué generará este código?
let x = 5; console.log(x++); a) 5 b) 6 c) '5++' d)
¿Qué generará este código?
const a = 5; console.log(a++); a) 5 b) 6 c) '5++' d)
La respuestad) error
Cuando se usa la forma de incriminación postfix, el valor se devuelve antes de aumentar.
Y con prefijo después, es decir console.log(++5)
imprimiría 6
no se puede sobrescribir const
; El número es primitivo, cuando se incrementa, la variable se sobrescribirá con el nuevo valor y habrá un error.
Conjunto:
¿Qué generará este código?
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)
La respuestab) [1, 2, indefinido, 3, 4, 5]
¿Qué generará este código?
let set = new Set([10, '10', new Number(10), 1e1, 0xA]); console.log(set.size); a) 5 b) 3 c) 2 d) 1
¿Qué generará este código?
let obj = {}; let set = new Set([obj, obj, {}, {}, {...{}}, {...obj}]); console.log(set.size); a) 6 b) 5 c) 2 d) 1
La respuestab) 5
Set
es un conjunto; por definición, no puede haber valores idénticos en él. La pregunta es cómo se comparan estos valores. Las primitivas se comparan por valor y los objetos por referencia.
En sí mismo no cita tipos de datos y puede almacenar valores de cualquier tipo 1e1
y 0xA
: se convertirá a un sistema decimal y obtendrá 10
.
Y los nuevos objetos no siempre son iguales: console.log({} == {})
devolverá false
ya que Los objetos se crearán de una manera nueva en diferentes lugares de la memoria y sus enlaces no serán iguales.
¿Qué generará este código?
console.log(Infinity / Infinity); a) NaN b) 1 c) Error d) Infinity
La respuestaa) NaN
Es imposible dividir el infinito en infinito y restar infinito de infinito ya que desde un punto de vista matemático, se obtiene incertidumbre, lo mismo sucederá cuando Infinity
multiplique Infinity
y 0
errores no causen operaciones matemáticas: habrá NaN
Preguntas sobre Spread:
¿Qué generará este código?
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)
La respuestaa) {a: 2, b: 2, c: 4, d: 8}
¿Qué generará este código?
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)
Respuesta + análisisb) [1, 2, [3, 4], 5, 6]
Spread
operador Spread
sirve para analizar un objeto o matriz en partes. Toma valores de la entidad después de ...
y los copia en la creada. Vale la pena señalar que para una matriz y un objeto se abre a 1 nivel, es decir ...[[1]]
devolverá una matriz con un elemento, no el elemento en sí. No puede haber valores duplicados en los objetos, por lo tanto, los valores revelados después serán sobrescritos por aquellos que fueron revelados previamente. Esto se puede usar para especificar la configuración predeterminada.
const fn = (actualProps) => ({ ...defaultProps, ...actualProps })
Todos los valores predeterminados serán anulados por los valores pasados, si los hay.
¿Qué generará este código?
console.log(parseInt(' -10,3 ')); a) -10,3 b) -10 c) TypeError d) NaN
Respuesta + análisisb) -10
Descripción exhaustiva con MDN :
Si la función parseInt encuentra un carácter que no es un número en el sistema numérico especificado, omite este y todos los caracteres posteriores (incluso si son adecuados) y devuelve un entero convertido de la parte de la cadena que precede a este carácter. parseInt corta la parte fraccionaria de un número. Se permiten espacios al principio y al final de una línea.
¿Qué generará este código?
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
Respuesta + análisisd) 12 12 18
Proxy
intercepta todas las llamadas al objeto. En este caso, representamos solo el método get
y siempre devolvemos 12
sin importar a qué campo del objeto estamos accediendo. En este caso, no tocamos establecer, y al acceder al proxy, el valor en el objeto será reemplazado.
matrices:
¿Qué generará este código?
let arr = []; arr[1] = 1; arr[5] = 10; console.log(arr.length); a) 1 b) 5 c) 6 d) 10
¿Qué generará este código?
let arr = new Array(3); console.log(arr[1]); a) undefined b) 1 c) 3 d)
Respuesta + análisisa) indefinido
Cuando creamos una Array
con un argumento numérico, significa la longitud de la matriz. Una matriz se crea vacía, todos los valores son undefined
. Lo mismo sucede si crea acceso a un campo de matriz inexistente. Vale la pena señalar que si pasa un número a Array
, se devolverá una matriz con este elemento, es decir Array('a')
devolverá ['a']
operaciones lógicas &&
, ||
, ==
, etc.
¿Qué generará este código?
console.log([] && 'foo' && undefined && true && false); a) [] b) 'foo' c) undefined d) true
¿Qué generará este código?
console.log(0 || 1 && 2 || 3); a) 0 b) 1 c) 2 d) 3
¿Qué generará este código?
console.log(0 || '' || 2 || undefined || true || false); a) 0 b) false c) 2 d) true
¿Qué generará este código?
console.log(2 && '1' && null && undefined && true && false); a) 2 b) false c) undefined d) null
¿Qué generará este código?
console.log([] && {} || null && 100 || ''); a) true b) 100 c) '' d) {}
Respuesta + análisisd) {}
Una matriz vacía []
es true
como lo es un objeto vacío {}
.
La cadena vacía ''
, null
e undefined
es false
Lógico o ||
- devuelve el operando izquierdo, si es verdadero, de lo contrario devuelve el operando derecho.
Lógico y &&
: devuelve el operando izquierdo, si es falso, de lo contrario devuelve el operando derecho.
Esto a veces se puede encontrar en el código, antes de la aparición de los parámetros predeterminados, a menudo escribían así: si no hay parámetros en la función, entonces tomamos los parámetros predeterminados:
function f(userParams) { var params = userParams || defaultParams; }
Ahora Reaccionar a menudo comprueba si la condición es verdadera, luego mostramos algo:
{ isDivVisible && <div>bla-bla</div> }
comparación de matriz:
¿Qué generará este código?
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)
¿Qué generará este código?
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]
La respuestad) [verdadero, verdadero, verdadero]
¿Qué generará este código?
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)
¿Qué generará este código?
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)
Respuesta + análisisb) verdadero
Cuando ==
comparar por referencia.
durante la operación >, >=, <, <=
operandos se convierten en primitivas y el método valueOf se llama en arrayFoo
, que debería devolver el valor primitivo arrayFoo
, pero devuelve una referencia a la misma matriz. A continuación, se produce una conversión a un valor primitivo llamando al método toString
, que a su vez devolverá una representación de cadena de la matriz en forma de "1,2,3,4" compara las dos matrices lexicográficamente y devuelve true
¿Qué generará este código?
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
Respuesta + análisisb) verdadero, verdadero, falso
Explicación completa con MDN :
El comportamiento de este método (hablando de Object.is
) no es el mismo que el operador ===
. El operador ===
(así como el operador ==
) considera los valores numéricos -0
y +0
iguales, y el valor Number.NaN
no Number.NaN
igual a sí mismo.
Preguntas sobre la elevación:
¿Qué generará este código?
console.log(str); const str = 'HeadHunter'; a) 'HeadHunter' b) undefined c)
¿Qué generará este código?
var arrayFunction = []; for (let i = 0; i <= 10; i++) { arrayFunction.push(() => i); } console.log(arrayFunction[3]()); a) 4 b) 0 c) 11 d) 3
¿Qué generará este código?
console.log(str); var str = 'HeadHunter'; a) 'HeadHunter' b) undefined c) null c)
¿Qué generará este código?
console.log(foo); var foo; foo = foo ? 1 : 0; console.log(foo); a) b) undefined 0 c) '' 1 d) 0 0
¿Funcionará una llamada de función?
getCompanyName(); function getCompanyName() { return 'HeadHunter'; } a) b) , . c)
¿Qué generará este código?
var arrayFunction = []; for (var i = 0; i <= 10; i++) { arrayFunction.push(() => i); } console.log(arrayFunction[3]()); a) 4 b) 0 c) 11 d) 3
Respuesta + análisisc) 11
Las declaraciones de funciones aparecen, pero no hay expresión.
var
aparece, pero hasta que la inicialización undefined
esté undefined
.
let
y const
no aparecen y tienen alcance en un bloque, es decir limitado a {}
.
Para que el bucle funcione correctamente con var
debe usar un cierre, el valor se guardará en él.
(Esto solía ser una tarea clásica para las entrevistas, pero ahora hemos dejado)
var arrayFunction = []; for (var i = 0; i <= 10; i++) { (function(i) { arrayFunction.push(() => i); })(i); } console.log(arrayFunction[3]());
¿Qué generará este código?
console.log(true + false); a) true b) false c) 1 d) 0
Respuesta + análisisc) 1
Ninguno de los operadores es una cadena, +
lleva a un número. Resulta 1 + 0
¿Qué generará este código?
console.log([] - 100 + ![]); a) false b) '-100' c) -100 d) NaN
Respuesta + análisisc) -100
El conjunto se convierte en una cadena, después de eso, debido a que -
convertimos a un número, resulta -100
, luego convertimos el conjunto a false
, y esto es 0
¿Qué generará este código?
console.log([[], []] + 1); a) 1 b) '1' c) ',1' d) NaN
Respuesta + análisisc) ', 1'
Llamamos toString
en el objeto, mientras que toString
también se llamará a todos los elementos de la matriz. [].toString
devolverá una cadena vacía ''
. Resulta que , + 1
- la respuesta ,1
.
¿Qué generará este código?
console.log([] + 100 + 5); a) 105 b) '1005' c) 1005 d) NaN
Respuesta + análisisb) '1005'
La matriz es reducible a una cadena, y luego ya ocurre la concatenación.
¿Qué generará este código?
console.log(1 + { a: 3 } + '2'); a) 6 b) '1[object Object]2' c) 3 d) NaN
Respuesta + análisisb) '1 [objeto Objeto] 2'
Convierte en una cadena: es solo concatenación.
¿Qué generará este código?
console.log(10.toString() + 10 + 0x1); a) '10101' b) 21 c) '10100x1' d)
Respuesta + análisisd) error
Para un número, un punto .
significa el comienzo de la parte fraccionaria, esperamos un número allí; habrá un error.
Para que este ejemplo funcione bien, debe escribir 10..toString()
¿Qué generará este código?
console.log(5 + false - null + true); a) '0true' b) NaN c) 6 d)
Respuesta + análisisc) 6
Aquí todo se reduce a un número, resulta 5 + 0 - 0 + 1
¿Qué generará este código?
console.log(true + NaN + false); a) true b) NaN c) false d) 1
Respuesta + análisisb) NaN
Reducimos todo a un número, cuando sumamos números con NaN
, obtenemos NaN
¿Qué generará este código?
console.log('0x1' + '1' - '1e1'); a) 17 b) 7 c) '0x111e1' d) NaN
Respuesta + análisisb) 7
Ya hay líneas después de la primera concatenación, obtenemos: '0x11' - '1e1'
. Debido al signo -
traemos todo a un número.
0x11
- El número hexadecimal en decimal es 17
.
1e1
- la forma exponencial es la misma que 1 * 10 ** 1
- es decir solo 10
.
tipo de:
¿Qué generará este código?
let foo = () => { return null; }; console.log( typeof typeof foo ); a) 'function' b) 'string' c) 'null' d)
¿Qué generará este código?
typeof function() {}.prototype; a) 'function' b) 'object' c) 'undefined' d)
Respuesta + análisisb) 'objeto'
typeof
siempre devuelve una cadena, tiene una prioridad más baja que llamar a la función, por lo que la función se ejecuta primero y typeof
se aplica al resultado que se le devuelve. Los objetos de función heredan de Function.prototype. Speck determina explícitamente que este es un objeto.
bucle de eventos:
Comencemos con 2 preguntas sobre promesas.
¿Qué generará este código?
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
¿Qué generará este código?
Promise.reject('foo') .then(() => Promise.resolve('bar'), () => {}) .then((a) => {console.log(a)}) a) foo b) bar c) undefined d)
Respuesta + análisisc) indefinido
Promise.reject
: devuelve una promesa en un estado rechazado.
Debe recordarse que then
toma 2 parámetros, onFulfill
y onReject
callbacks. Si se produce un error antes de esto, entonces llegamos a la onReject
llamada onReject
. Si no hay ningún error, entonces llegaremos a onFulfill
then
. Y no olvide que () => {}
no devuelve un objeto vacío, sino undefined
, para devolver un objeto vacío, debe escribir así: () => ({})
El orden de las tareas.
¿Qué generará este código?
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
¿Qué generará este código?
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
La respuestab) después, en promesa, en tiempo de espera
¿Qué generará este código?
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
¿Qué generará este código?
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
¿Qué generará este código?
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'
Respuesta + análisisc) 1, 2, 3, 'promesa1 resuelta', 'setTimeout'
Primero, todas las llamadas síncronas se activan, después de eso, cuando la pila de llamadas está vacía, lo que está en la cola se llama (tareas asincrónicas). Primero, microtask: promesas y mutation observer
. Al final de la tarea actual, se ejecutan todas las microtask, en relación con esta microtask puede bloquear el bucle de eventos, después de completar la tarea en el navegador, se realiza la representación. Después de eso, macro tareas: se ejecutan los tiempos de espera.
Este es un ejemplo muy simplificado, con más detalle le recomendaría que vea el discurso de Mikhail Bashurov
Y la última pregunta promete vs espera
¿Qué generará este código?
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
Respuesta + análisisc) 2 3 1
De acuerdo con la especificación, las promesas agregadas hasta then
primero deben ejecutarse, y solo después de eso debe continuar
ejecución de una función asincrónica. Mota Para una comprensión más detallada de por qué esto es así, le aconsejo que lea un excelente artículo en v8.dev