¿Desea prepararse para una entrevista de JavaScript y está buscando preguntas para practicar? Si es así, considere que su búsqueda ha terminado. El autor del material, cuya traducción publicamos hoy, dice que ha recopilado más de dos docenas de preguntas en JavaScript destinadas a aquellos que desean pasar de ser junior a senior, para aquellos que buscan pasar con éxito una entrevista en el campo del desarrollo front-end y obtener una oferta interesante de el empleador.

1. Explicar las características de validación de igualdad de JavaScript
Dificultad: *
JavaScript tiene dos operadores para verificar la igualdad de valores. El primero es el llamado operador de igualdad estricta. El segundo es el operador de igualdad no estricto, que se puede utilizar para convertir los tipos de cantidades controladas.- El operador de igualdad estricta (
===
) verifica los valores de igualdad sin realizar conversiones de tipo. - El operador de igualdad no estricto (
==
) verifica los valores de igualdad, convirtiéndolos en un tipo común.
var a = "42";
var b = 42;
a == b;
a === b;
Aquí hay algunas pautas para usar varios verificadores de igualdad en JavaScript:- Si alguno de los valores comparados puede ser un valor
true
o false
, intente evitar el operador ==
. Utiliza un operador ===
. - Utilice el operador
===
en caso de que si se está trabajando con los siguientes valores: 0
, «»
o []
(matriz vacía). - En todos los demás casos, puede utilizar el operador de forma segura
==
. Además, esto no solo es seguro, sino que también ayuda a simplificar el código y mejorar su legibilidad.
→ Fuente2. Dé ejemplos de conversión a un tipo lógico de valores que no están relacionados con este tipo
Dificultad: ***
La esencia de esta pregunta es descubrir qué valores, en el caso de convertirlos a un tipo lógico, se convierten en false
, y cuáles - en true
.Aquí hay una lista de valores que se pueden llamar "falsos". Ellos, al convertir a un tipo lógico, se convierten en un valor false
:«»
(línea vacía)0
, -0
, NaN
(No es un número).null
, undefined
.
"Falso" es un significado lógico false
.Cualquier valor que no esté incluido en esta lista, cuando se convierte a un tipo lógico, se convierte en true
(dichos valores se denominan "verdadero" - verdad). Por ejemplo:«hello»
.42
.[ ]
, [ 1, «2», 3 ]
(matrices).{ }
, { a: 42 }
(objetos).function foo() { .. }
(funciones).
"Verdadero" es también un significado lógico true
.→ Fuente3. ¿Qué es el IIFE?
Dificultad: ***
IIFE (Expresión de función invocada inmediatamente) es una expresión funcional invocada de inmediato. Dicha expresión se ejecuta inmediatamente después de la creación.(function IIFE(){
console.log( "Hello!" );
})();
Este patrón se usa a menudo para evitar la contaminación del espacio de nombres global. El hecho es que las variables declaradas en IIFE (como en cualquier otra función ordinaria) son invisibles fuera de esta función.→ Fuente4. ¿Cuándo debo usar las funciones de flecha que aparecieron en ES6?
Dificultad: ***
Aquí hay reglas simples para usar las diversas formas de declarar las funciones que sigo al desarrollar código para entornos que admiten ES6 y estándares más nuevos:- Use la palabra clave
function
en el ámbito global y para las propiedades Object.prototype
. - Use la palabra clave
function
para constructores de objetos. - En otros casos, use las funciones de flecha.
Como puede ver, se recomienda utilizar las funciones de flecha en casi todas partes. Hay varias razones para este estado de cosas:- Trabajo conveniente con contexto. Las funciones de flecha usan el valor del
this
contexto circundante sin tener el suyo this
. Si tales funciones se usan secuencialmente, sin usar funciones ordinarias en construcciones complejas, esto garantiza un trabajo seguro con el contexto. - Compacidad El código de función de flecha es más fácil de ingresar y más fácil de leer. Quizás esta ventaja de las funciones de flecha sobre las normales le parecerá controvertida y dependerá del punto de vista de cada desarrollador específico.
- Código de claridad. Si casi todo el código está representado por funciones de flecha, cualquier función ordinaria se distingue en dicho código creando su propio contexto. Usando las funciones de flecha, el programador crea un código más comprensible en el que es más fácil trabajar que en el código sin funciones de flecha
this
.
→ Fuente5. ¿Cuál es la diferencia entre las clases ES6 y los constructores de funciones?
Dificultad: ***
Veamos algunos ejemplos primero.Función del constructor:function Person(name) {
this.name = name;
}
Clase ES6:class Person {
constructor(name) {
this.name = name;
}
}
Cuando se trata de crear objetos simples, los constructores y las clases utilizados para este propósito se ven muy similares.La principal diferencia entre constructores y clases aparece cuando se usa la herencia. Si necesitamos crear una clase Student
que sea una subclase de la clase Person
y agregar un campo a esta nueva clase studentId
, así es como se verá el código en el que se usan los constructores y el código en el que se usan las clases.Función del constructor:function Student(name, studentId) {
Person.call(this, name);
this.studentId = studentId;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Clase ES6:class Student extends Person {
constructor(name, studentId) {
super(name);
this.studentId = studentId;
}
}
→ Fuente6. Cuéntanos sobre el método Function.prototype.bind ().
Dificultad: ***
Para citar MDN: “El método bind()
crea una nueva función que, cuando se llama, establece el this
valor proporcionado como el contexto de ejecución . El conjunto de argumentos también se pasa al método, que se establecerá antes de que los argumentos pasen a la función enlazada cuando se llama ".Yo creo en ese método. bind()
especialmente útil para enlazar valores this
en métodos de clase que deben pasarse a otras funciones. Esta técnica se usa a menudo en componentes React.→ Fuente 7. ¿Para qué se usan comúnmente las funciones anónimas?
Dificultad: ***
Las funciones anónimas se utilizan para crear construcciones IIFE, las variables declaradas en las que no contaminan el alcance global.(function() {
})();
Las funciones anónimas se usan como funciones de devolución de llamada, que se usan solo en un lugar del programa. El código se verá más autosuficiente y legible si la devolución de llamada se anuncia directamente en el lugar donde se usa. Esto elimina la necesidad de mirar el código en busca del cuerpo de la función.setTimeout(function() {
console.log('Hello world!');
}, 1000);
Las funciones anónimas se usan convenientemente en construcciones específicas del estilo de programación funcional, o cuando se trabaja con bibliotecas como Lodash (este caso de uso es similar a su uso como devoluciones de llamada).const arr = [1, 2, 3];
const double = arr.map(function(el) {
return el * 2;
});
console.log(double);
→ Fuente8. ¿Cuál es la diferencia entre el método Object.freeze () y la palabra clave const?
Dificultad: ***
La palabra clave const
y el método Object.freeze()
son cosas completamente diferentes.La palabra clave se const
aplica a los enlaces (a "variables"). Crea un enlace inmutable, es decir, es const
imposible vincular algo nuevo a una variable (constante) declarada usando una palabra clave . A una constante no se le puede asignar un nuevo valor.const person = {
name: "Leonardo"
};
let animal = {
species: "snake"
};
person = animal;
El método Object.freeze()
funciona con valores. O más bien, con valores de objeto. Hace que el objeto sea inmutable, lo que protege contra cambios en el valor de las propiedades de este objeto.let person = {
name: "Leonardo"
};
Object.freeze(person);
person.name = "Lima";
console.log(person);
Tenga en cuenta que el mensaje de error se muestra en modo estricto. En modo normal, la operación de cambiar la propiedad de un objeto "congelado" simplemente no funciona.→ Fuente9. ¿Qué es un "generador"?
Dificultad: ***
Los generadores son funciones desde las cuales puede "salir" y en las que puede "entrar" según sea necesario. Su contexto (enlaces variables) se mantiene entre sesiones de "entrada" en ellos. Los generadores se declaran usando una palabra clave function*
. Dicha función, cuando se llama por primera vez, no ejecuta el código, devolviendo un objeto especial, un generador, que le permite controlar su ejecución. Para obtener el siguiente valor emitido por el generador, debe llamar a su método next()
. Debido a esto, el código de función se ejecuta hasta que encuentra una palabra clave yield
que devuelve un valor.La función del generador se puede invocar tantas veces como desee. Cada vez que un nuevo generador regresará. Pero cada generador se puede omitir solo una vez.function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
let iterationCount = 0;
for (let i = start; i < end; i += step) {
iterationCount++;
yield i;
}
return iterationCount;
}
→ Fuente10. ¿Cuándo deben usarse los generadores?
Dificultad: ***
Si, en pocas palabras, describe las principales características útiles de los generadores, resulta que son las siguientes:- El código en el que se usa el generador determina el momento en que se recibe el siguiente valor. El generador solo es responsable de devolver los valores, se controla desde el exterior.
- Hay generadores asincrónicos. Le permiten trabajar con flujos de datos asincrónicos.
Lo principal en los generadores es que puede obtener el siguiente valor devuelto por el generador solo cuando es necesario en el código que usa el generador. Los generadores no devuelven todo de una vez. En algunas situaciones, esta característica puede ser muy conveniente.→ Fuente11. ¿Qué es "elevar variables"?
Dificultad: ****
La esencia del concepto de "elevar variables" es que los anuncios "suben" a la cima del alcance actual. Como resultado, la variable se puede usar antes de su declaración. Solo se generan declaraciones de variables, pero no su código de inicialización. Tenga en cuenta que el comportamiento de las variables declaradas con la palabra clave var
es diferente del comportamiento de las variables y constantes declaradas con let
y const
.→ Fuente12. ¿Cuál será el siguiente código de salida?
Dificultad: ****
var output = (function(x) {
delete x;
return x;
})(0);
console.log(output);
Este código saldrá 0
. El operador se delete
utiliza para eliminar las propiedades de los objetos. Y x
, esto no es una propiedad de objeto, es una variable local. El operador delete
no afecta a las variables locales.→ Fuente13. ¿Cuál será el siguiente código de salida?
Dificultad: ****
var Employee = {
company: 'xyz'
}
var emp1 = Object.create(Employee);
delete emp1.company
console.log(emp1.company);
Este código saldrá xyz
. Una propiedad company
no es una propiedad de un objeto emp1
, sino una propiedad de su prototipo. El operador delete
no elimina las propiedades prototipo de los objetos. Un objeto emp1
no tiene su propia propiedad company
. Puede verificar esto mediante:console.log(emp1.hasOwnProperty('company'));
Si aún necesitamos eliminar esta propiedad, puede hacerlo contactando directamente al objeto Employee
( delete Employee.company
) o contactando al prototipo del objeto emp1
utilizando su propiedad __proto__
( delete emp1.__proto__.company
).→ Fuente14. Cuéntanos sobre el patrón de diseño del prototipo.
Dificultad: ****
El prototipo es un patrón de diseño genérico. Se usa para crear objetos. Los objetos creados con él contienen valores copiados de su prototipo (del objeto de muestra). Esta plantilla también se denomina plantilla de Propiedades.Un ejemplo del uso del patrón "prototipo" es la inicialización de ciertos objetos con valores estándar almacenados en la base de datos. Dichos valores registrados en el prototipo se copian en nuevos objetos sin acceder a la base de datos.Cabe señalar que este patrón rara vez se usa en los idiomas clásicos. JavaScript utiliza un modelo de herencia prototipo. Este patrón se utiliza en el diseño de nuevos objetos y sus prototipos.→ Fuente15. ¿Qué es una "zona muerta temporal" en ES6?
Dificultad: ****
El ES6 realizó el levantamiento de variables y constantes declaradas usando las palabras clave let
y const
(esto se hace y el aumento de la entidad declarada usando palabras clave var
, class
y function
). Sin embargo, el código tiene una zona que se extiende desde la entrada en el alcance hasta la declaración de una variable o constante. Al acceder a una variable o constante en esta zona, se generará un error. Esta es la "Zona muerta temporal" (TDZ).
let aLet;
console.log(aLet);
aLet = 10;
console.log(aLet);
En este ejemplo, el TDZ termina después de la declaración aLet
, pero no después de aLet
que se asigna el valor.→ Fuente16. ¿Puedes describir la diferencia principal entre los métodos de matriz forEach () y map ()? ¿En qué situaciones preferiría uno de estos métodos a otro?
Dificultad: ****
Para comprender la diferencia entre estos métodos, hablemos sobre las características de cada uno de ellos.Así es como funciona .forEach()
:- Se itera sobre los elementos de la matriz.
- Realiza la función de devolución de llamada que se le pasa para cada elemento de la matriz.
- No devuelve nada.
const a = [1, 2, 3];
const doubled = a.forEach((num, index) => {
});
Aquí hay una breve descripción del método .map()
:- Se itera sobre los elementos de la matriz.
- Convierte cada elemento de la matriz original en un elemento de la nueva matriz, llamando a la función que se le pasa para cada elemento de la matriz original.
const a = [1, 2, 3];
const doubled = a.map(num => {
return num * 2;
});
Como resultado, resulta que la principal diferencia entre .forEach()
y .map()
es que .map()
devuelve una nueva matriz. Si necesita obtener el resultado de convertir los elementos de la matriz original sin cambiar esta matriz, entonces debe elegir .map()
. Si solo necesita iterar sobre los elementos de la matriz, puede usarlo .forEach()
.→ Fuente17. ¿Cuál es la diferencia entre una variable no declarada, una variable que contiene un valor nulo y una variable indefinida? ¿Cómo verificar una variable por el hecho de que no está declarada, así como nula e indefinida?
Dificultad: ****
Se crea una variable no declarada cuando se asigna un valor a un identificador que no se declaró previamente mediante var
, let
o const
. Las variables no declaradas se declaran en el ámbito global, fuera del ámbito actual. En modo estricto, se produce una excepción al intentar asignar un valor a una variable no declarada ReferenceError
. No se recomienda el uso de variables no declaradas, al igual que no se recomienda el uso de variables globales. Deben evitarse por todos los medios. Para protegerse de las consecuencias del uso de variables no declaradas, use el bloque try/catch
.function foo() {
x = 1;
}
foo();
console.log(x);
Una variable que contiene undefined
es una variable declarada a la que no se le asigna un valor. El valor undefined
forma su propio tipo de datos. Si la función no devuelve nada y el resultado de su llamada se escribe en una variable, caerá en esta variable undefined
. Para organizar una verificación undefined
, puede usar el operador de igualdad estricta ( ===
) o el operador typeof
que devuelve una cadena undefined
. Tenga en cuenta que cuando se verifica, undefined
no se debe utilizar la no-operador de igualdad estricta ( ==
), ya que considera que el undefined
y los valores a ser igual null
.var foo;
console.log(foo);
console.log(foo === undefined);
console.log(typeof foo === 'undefined');
console.log(foo == null);
function bar() {}
var baz = bar();
console.log(baz);
Una variable que contiene un valor null
debe establecerse explícitamente en este valor. Simboliza la ausencia de significado y difiere de undefined
-variable en que el valor en él se le asignó explícitamente. Para verificar el valor null
, es suficiente usar el operador de igualdad estricta. Para verificar null
, como en el caso de verificar undefined
, no se debe usar el operador de igualdad no estricto, que considera los valores de null
e igual undefined
.var foo = null;
console.log(foo === null);
console.log(typeof foo === 'object');
console.log(foo == undefined);
Intento nunca dejar variables en un estado no declarado, o en un estado donde se declaran, pero no se les asigna ningún valor explícitamente. Si no voy a escribir un valor en una variable inmediatamente después de su declaración, lo escribo null
. Si usa un linter, generalmente informa casos de uso de variables no declaradas.→ Fuente18. Cuéntanos sobre el módulo de diseño "Módulo abierto"
Dificultad: *****
La plantilla "Módulo revelador" es una variación de la plantilla "Módulo". El propósito de usar este patrón es admitir la encapsulación y descubrir algunas propiedades y métodos devueltos en el objeto literal. Así se verá la implementación directa de esta plantilla:var Exposer = (function() {
var privateVariable = 10;
var privateMethod = function() {
console.log('Inside a private method!');
privateVariable++;
}
var methodToExpose = function() {
console.log('This is a method I want to expose!');
}
var otherMethodIWantToExpose = function() {
privateMethod();
}
return {
first: methodToExpose,
second: otherMethodIWantToExpose
};
})();
Exposer.first();
Exposer.second();
Exposer.methodToExpose;
El inconveniente obvio de esta plantilla es que no puede usar métodos privados cuando la usa.→ Fuente19. ¿Cuál es la diferencia entre los objetos Map y WeakMap?
Dificultad: *****
Estos objetos se comportan de manera diferente si una variable que contiene una referencia a un objeto que es la clave de uno de los pares clave / valor no está disponible. Aquí hay un ejemplo:var map = new Map();
var weakmap = new WeakMap();
(function() {
var a = {
x: 12
};
var b = {
y: 12
};
map.set(a, 1);
weakmap.set(b, 2);
})()
Una vez completada la ejecución de IIFE, ya no tendremos acceso a los objetos a
y b
. Por lo tanto, el recolector de basura elimina la clave b
de weakmap
y borra la memoria. Pero el contenido map
sigue siendo el mismo.Como resultado, resulta que los objetos WeakMap
permiten al recolector de basura deshacerse de aquellos registros que no están referenciados en variables externas. Los objetos map
almacenan pares clave / valor independientemente de la presencia o ausencia de referencias clave externas. Lo mismo puede decirse sobre la implementación de la estructura de datos Map
utilizando matrices ordinarias. Se WeakMap
utilizan las referencias clave "débiles". No interfieren con el funcionamiento del recolector de basura si no hay otras referencias al objeto utilizado como clave.→ Fuente20. ¿Cómo se pasan los parámetros a la función JavaScript: por referencia o por valor?
Dificultad: *****
Los parámetros siempre se pasan por valor, pero las referencias a objetos se escriben en variables que representan objetos. Por lo tanto, cuando un objeto se transfiere a una función y se cambia la propiedad de este objeto, este cambio se guarda en el objeto incluso cuando la función sale. Como resultado, existe la sensación de que los parámetros en la función se pasan por referencia. Pero si cambia el valor de la variable que representa el objeto, este cambio no afectará a los objetos que están fuera de la función.Aquí hay un ejemplo:function changeStuff(a, b, c)
{
a = a * 10;
b.item = "changed";
c = {item: "changed"};
}
var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};
changeStuff(num, obj1, obj2);
console.log(num);
console.log(obj1.item);
console.log(obj2.item);
Esto es lo que generará este código:10
changed
unchanged
→ Fuente21. ¿Cómo organizar una "congelación profunda" de un objeto?
Dificultad: *****
Para proporcionar la "congelación profunda" de un objeto usando Object.freeze()
, debe crear una función recursiva que "congele" las propiedades del objeto, que también son objetos.Aquí hay un ejemplo de una "congelación" ordinaria de un objeto:let person = {
name: "Leonardo",
profession: {
name: "developer"
}
};
Object.freeze(person);
person.profession.name = "doctor";
console.log(person);
Aquí está la "congelación profunda":function deepFreeze(object) {
let propNames = Object.getOwnPropertyNames(object);
for (let name of propNames) {
let value = object[name];
object[name] = value && typeof value === "object" ?
deepFreeze(value) : value;
}
return Object.freeze(object);
}
let person = {
name: "Leonardo",
profession: {
name: "developer"
}
};
deepFreeze(person);
person.profession.name = "doctor";
El mensaje de error se muestra solo en modo estricto. En modo normal, el valor no cambia sin mensajes de error.→ Fuente22. ¿Por qué los programadores de JavaScript tienen problemas para usar esta palabra clave?
Dificultad: *****
Lo más importante a entender this
es que las funciones no tienen un valor fijo this
. Este valor depende de cómo se llama la función. Si decimos que se llama a una función con algún valor específico this
, esto significa que este valor se determina no durante la declaración de la función, sino durante su llamada. Aquí hay algunas características this
:- Si la función se llama en la forma habitual (es decir, usando la construcción de vista
someFunc()
), se this
referirá al objeto global (en el navegador esto window
). Si el código se ejecuta en modo estricto, this
se escribirá un valor undefined
. - Si la función se llama como método de un objeto, la palabra clave
this
estará representada por el objeto al que pertenece el método. - call apply,
this
, call
apply
. - ,
this
. - ,
new
, this
, prototype
-. - Si la función se ha creado usando el aprieto método , entonces la
this
función de palabras clave estará vinculado rígidamente al valor pasado bind
como primer argumento. Esta es la única excepción a la regla de que las funciones no tienen un valor codificado this
. Las funciones creadas usando bind
son inmutables this
.
→ Fuente23. Compare el uso de la construcción y generadores asíncronos / en espera para implementar la misma funcionalidad
Dificultad: *****
- Al iterar un generador utilizando un método,
.next()
cada llamada a este método devuelve un solo valor utilizando la palabra clave yield
. Cuando se utiliza la construcción async / await, las expresiones de wait se ejecutan secuencialmente. - El diseño asíncrono / espera simplifica la implementación de un caso de uso de generador específico.
- Los valores devueltos por el generador siempre tienen la forma
{value: X, done: Boolean}
, y las funciones asincrónicas devuelven las promesas resueltas con el valor X
, o fallan. - Una función asincrónica se puede convertir en un generador mediante promesas. El siguiente es un ejemplo de tal conversión.
Aquí está la función asincrónica:
async function init() {
const res1 = await doTask1();
console.log(res1);
const res2 = await doTask2(res1);
console.log(res2);
const res3 = await doTask3(res2);
console.log(res3);
return res3;
}
init();
Aquí hay un generador similar.
function runner(genFn) {
const itr = genFn();
function run(arg) {
let result = itr.next(arg);
if (result.done) {
return result.value;
} else {
return Promise.resolve(result.value).then(run);
}
}
return run;
}
runner(function* () {
const res1 = await doTask1();
console.log(res1);
const res2 = await doTask2(res1);
console.log(res2);
const res3 = await doTask3(res2);
console.log(res3);
return res3;
});
→ FuenteEstimados lectores! ¿Qué preguntas de JavaScript se te ocurrieron durante tus entrevistas?