[Preguntas de la entrevista inicial] Preguntas de la entrevista inicial 2023 - Capítulo JS

Siempre hay altibajos en la vida de una persona. No siempre saldrá como el sol naciente, ni siempre será miserable. Los altibajos repetidos son entrenamiento para una persona. Por lo tanto, aquellos que flotan arriba no necesitan estar orgullosos; aquellos que se hunden abajo no necesitan ser pesimistas. Debemos ser francos y humildes, optimistas y emprendedores, y seguir adelante. ——Konosuke Matsushita

Hola a todos, mi nombre es Jiang Chen. En el entorno actual de Internet, todo el mundo debe haberlo sentido hasta cierto punto. En esta sociedad impetuosa, sólo manteniendo constantemente el carácter se pueden percibir diferentes beneficios y animarse unos a otros.

Una colección de las últimas preguntas de las entrevistas de 2023, así que esté preparado en todo momento.

Este artículo se publicó por primera vez en la cuenta pública de WeChat: Programador salvaje Jiang Chen

Todos son bienvenidos a dar me gusta, coleccionar y seguir.

Lista de artículos

Describe esto brevemente en JavaScript.

en JS thises un concepto relativamente complejo que no se puede explicar claramente en unas pocas oraciones. En términos generales, la forma en que se llama la función determina thisel valor de. He leído muchos thisartículos en Internet sobre y Arnav Aggrawal lo escribió con mayor claridad. thisEl valor cumple con las siguientes reglas:

Utilice la palabra clave al llamar a una función new, y el interior de la función thises un objeto completamente nuevo.
Si el método apply、callo bindse usa para llamar o crear una función, dentro de la función thises el objeto pasado a estos métodos como parámetro.
Cuando se llama a una función como método en un objeto, dentro de la función thisestá el objeto que llamó a la función. Por ejemplo, cuando obj.method()se llama, la función interna thisestará vinculada objal objeto.
Si la función que llama no cumple con las reglas anteriores, entonces thisel valor de apunta al objeto global ( global object). En un entorno de navegador, thisel valor de apunta al windowobjeto, pero en modo estricto ( 'use strict'), thisel valor de undefined.
Si se cumple más de una de las reglas anteriores, la regla más alta (el número 1 es la más alta, el número 4 es la más baja) determinará thisel valor de .
Si la función es ES2015una función de flecha en , todas las reglas anteriores se ignoran y thisse establecen en el contexto en el que se creó.

Cuéntame lo que sabes sobre AMD y CommonJS.

Todas son formas de implementar un sistema modular. Hasta ES2015la aparición de , JavaScriptno existía un sistema modular. CommonJSes sincrónico, mientras que AMD(Asynchronous Module Definition)por el nombre completo se desprende claramente que es asincrónico. CommonJSestá diseñado teniendo en cuenta el desarrollo del lado del servidor y AMDadmite la carga asincrónica de módulos, lo cual es más adecuado para navegadores.

Encuentro AMDque la sintaxis es muy detallada y CommonJSmás cercana al importuso de declaraciones en otros idiomas. En la mayoría de los casos, creo AMDque no es necesario usarlo, porque si JavaScriptagrupa todo en un archivo, no obtendrá los beneficios de la carga asincrónica. Además, CommonJSla sintaxis se acerca más al Nodeestilo de escribir módulos: JavaScriptal cambiar entre desarrollo front-end y back-end, la sobrecarga de cambio de contexto es menor.

Me alegra ver ES2015que el esquema de carga del módulo admite tanto sincrónico como asincrónico, y finalmente podemos usar solo un esquema. Si bien aún no está completamente implementado en los navegadores Node, podemos convertirlo usando herramientas de transcodificación.

Explique por qué el siguiente código no se puede utilizar como IIFE: function foo(){ }();. ¿Qué modificaciones se deben realizar para convertirlo en un IIFE?

IIFE (Expresiones de funciones invocadas inmediatamente) significa Expresiones de funciones invocadas inmediatamente. JavaScriptEl analizador function foo(){ }();analizará function foo(){ }和();. Entre ellos, el primero es una declaración de función; el segundo (un par de paréntesis) es un intento de llamar a una función sin especificar un nombre, por lo que arrojará un Uncaught SyntaxError: Unexpected token )error.

El método de modificación es: agregar otro par de corchetes, hay dos formas: (function foo(){ })()y (function foo(){ }()). La función anterior no estará expuesta al alcance global. Si no necesita hacer referencia a sí misma dentro de la función, puede omitir el nombre de la función.

Puede utilizar voidel operador: void function foo(){ }();. Sin embargo, este enfoque es problemático. El valor de la expresión es undefined, por lo que si IIFEtiene un valor de retorno, no utilice este enfoque. Por ejemplo

const foo = void (function bar() {
  return 'foo';
})();

console.log(foo); // undefined

¿Cuál es la diferencia entre variables nulas, indefinidas y no declaradas? ¿Cómo comprobar y juzgar estos valores de estado?

Cuando asigna un valor a una variable sin declararlo con var、leto por adelantado const, la variable es una variable no declarada ( undeclared variables). Las variables no declaradas abandonarán el alcance actual y se convertirán en variables definidas en el alcance global. En modo estricto, asignar un valor a una variable no declarada generará ReferenceErrorun error. Al igual que el uso de variables globales, el uso de variables no declaradas también es una muy mala práctica y debe evitarse siempre que sea posible. Para comprobarlos, coloque el código que los utiliza en try/catchuna declaración.

function foo() {
  x = 1; // 在严格模式下,抛出 ReferenceError 错误
}

foo();
console.log(x); // 1

Cuando una variable ha sido declarada pero no se le ha asignado un valor, el valor de la variable es undefined. Si el resultado de la ejecución de una función se asigna a una variable, pero la función no devuelve ningún valor, entonces el valor de la variable es undefined. Para comprobarlo, utilice igualdad estricta ( ===); alternativamente typeof, devuelve 'undefined'una cadena. Tenga en cuenta que no puede usar igualdad no estricta ( ==) para verificar porque nullel uso de igualdad no estricta también devolverá si el valor de la variable es true.

var foo;
console.log(foo); // undefined
console.log(foo === undefined); // true
console.log(typeof foo === 'undefined'); // true

console.log(foo == null); // true. 错误,不要使用非严格相等!

function bar() {}
var baz = bar();
console.log(baz); // undefined

nullSolo se puede asignar explícitamente a variables. Representa un valor nulo, que es diferente de ser asignado explícitamente undefined. Para comprobar el nullvalor del predicado, utilice el operador de igualdad estricta. Tenga en cuenta que, como antes, no puede usar igualdad no estricta ( ==) para verificar, porque undefinedel uso de igualdad no estricta también devolverá si el valor de la variable es true.

var foo = null;
console.log(foo === null); // true

console.log(foo == undefined); // true. 错误,不要使用非严格相等!

Como hábito personal, nunca uso variables no declaradas. Si se definen variables que aún no se utilizan, les asignaré valores explícitamente después de declararlas comonull

¿Qué es un cierre y por qué lo utilizamos?

Un cierre es una combinación de una función y el entorno léxico en el que se declara la función. El dominio utilizado en el ámbito léxico está determinado por el lugar donde se declara la variable en el código. Un cierre es una función que aún puede acceder al alcance de la función externa (encierra) incluso si es devuelta por la función externa.

¿Por qué utilizar cierres?

  • Utilice cierres para privatizar datos o simular métodos privados. Este enfoque también se denomina modo módulo ( module pattern).
  • Función de argumento parcial ( partial applications) curry ( currying).

Explique la principal diferencia entre el bucle .forEach y el bucle .map(). ¿En qué circunstancias se utilizan?

Para comprender la diferencia entre los dos, veamos lo que hacen.

para cada

  • Iterar sobre los elementos de una matriz.
  • Ejecutar devolución de llamada para cada elemento.
  • Sin valor de retorno.
const a = [1, 2, 3];
const doubled = a.forEach((num, index) => {
  // 执行与 num、index 相关的代码
});

// doubled = undefined

mapa

  • Iterar sobre los elementos de una matriz.
  • Se crea una nueva matriz "asignando" cada elemento a un nuevo elemento llamando a una función en cada elemento.
const a = [1, 2, 3];
const doubled = a.map((num) => {
  return num * 2;
});

// doubled = [2, 4, 6]

.forEach.map()La principal diferencia entre y es que .map()devuelve una nueva matriz. Si desea obtener un resultado sin cambiar la matriz original, utilice .map(). Si solo necesita realizar modificaciones iterativas en una matriz, utilice forEach.

¿Cuáles son los escenarios de aplicación típicos de funciones anónimas?

Las funciones anónimas se pueden utilizar en IIFE para encapsular código en el ámbito local de modo que las variables que declaran no estén expuestas al ámbito global.

(function () {
  // 一些代码。
})();

Las funciones anónimas se pueden usar como funciones de devolución de llamada que se usan solo una vez y no es necesario usarlas en ningún otro lugar. Cuando las funciones del controlador se definen dentro del programa que las llama, el código es más autónomo y legible, y se ahorra la molestia de encontrar la ubicación del cuerpo de la función del controlador.

setTimeout(function () {
  console.log('Hello world!');
}, 1000);

Las funciones anónimas se pueden utilizar en programación funcional o Lodash (similar a las funciones de devolución de llamada).

const arr = [1, 2, 3];
const double = arr.map(function (el) {
  return el * 2;
});
console.log(double); // [2, 4, 6]

¿Cuál es la diferencia entre .call y .apply?

.cally .applyambos se usan para llamar a una función, el primer parámetro se usará como thisvalor dentro de la función. Sin embargo, .callacepta parámetros separados por comas como siguiente parámetro, mientras que .applyacepta una matriz de parámetros como siguiente parámetro. Un método de memoria simple calles asociar la C a la separación por coma ( comma-separated) applyy asociar la A a la matriz ( array).

function add(a, b) {
  return a + b;
}

console.log(add.call(null, 1, 2)); // 3
console.log(add.apply(null, [1, 2])); // 3

Explique el uso de Function.prototype.bind.

Extraído de MDN:

El método bind() crea una nueva función y, cuando se llama, establece su palabra clave this en el valor proporcionado. Al llamar a la nueva función, proporciona una secuencia determinada de argumentos antes de cualquier suministro.

En mi experiencia, thises muy útil vincular el valor de a un método de una clase que desea pasar a otras funciones. ReactEsto suele hacerse en componentes .

Explique Ajax con el mayor detalle posible.

Ajax (JavaScript y XML asíncronos) es una tecnología de desarrollo web que utiliza muchas tecnologías web en el cliente para crear aplicaciones web asíncronas. Con Ajax, las aplicaciones web pueden enviar y recuperar datos hacia y desde el servidor de forma asincrónica (en segundo plano) sin interferir con la visualización y el comportamiento de las páginas existentes. Al separar la capa de intercambio de datos de la capa de presentación, Ajax permite que las páginas web y las aplicaciones web extendidas cambien dinámicamente el contenido sin recargar toda la página. De hecho, XML ahora se reemplaza a menudo por JSON debido al soporte nativo de JavaScript para JSON.

XMLHttpRequest APIA menudo se utiliza para comunicación asincrónica. También los hay recientemente populares fetch API.

¿Cuáles son las ventajas y desventajas de usar Ajax?

ventaja
  • Mejor interactividad. El contenido nuevo del servidor se puede cambiar dinámicamente sin recargar toda la página.
  • Reduce las conexiones al servidor ya que los scripts y estilos solo deben solicitarse una vez.
  • El estado se puede mantener en una página. Las variables de JavaScript y el estado DOM se mantienen porque la página del contenedor principal no se recarga.
  • Básicamente incluye la mayoría de las ventajas del SPA.
defecto
  • Las páginas web dinámicas son difíciles de recopilar.
  • No tiene ningún efecto si JavaScript ha sido deshabilitado en el navegador.
  • Algunos rastreadores web no ejecutan JavaScript y no verán el contenido cargado mediante JavaScript.
  • Básicamente incluye la mayoría de las deficiencias del SPA.

Explique cómo funciona JSONP y por qué no es cierto Ajax.

JSONP (JSON con relleno) es un método comúnmente utilizado para evitar las restricciones entre dominios en los navegadores web porque Ajax no permite solicitudes entre dominios.

JSONP <script>envía solicitudes entre dominios a través de etiquetas, generalmente utilizando callbackparámetros de consulta, como: https://example.com?callback=printData. Luego, el servidor envuelve los datos en una printDatafunción llamada y los devuelve al cliente.

<!-- https://mydomain.com -->
<script>
  function printData(data) {
    console.log(`My name is ${data.name}!`);
  }
</script>

<script src="https://example.com?callback=printData"></script>
// 文件加载自 https://example.com?callback=printData
printData({name: 'Yang Shun'});

El cliente debe tener la función en su alcance global printData, y la función será ejecutada por el cliente cuando se reciba una respuesta del dominio cruzado.

JSONP puede tener algunas implicaciones de seguridad. Dado que JSONP es una implementación de JavaScript pura, puede hacer todo lo que JavaScript puede hacer, por lo que se debe confiar en el proveedor de datos JSONP.

Hoy en día, el intercambio de recursos entre orígenes (CORS) es el método principal recomendado, y JSONP se ha considerado un método más complicado.

Por favor explique la elevación variable.

El levantamiento de variables es un término utilizado para explicar el comportamiento de las declaraciones de variables en el código. varLas variables declaradas o inicializadas usando la palabra clave "elevan" la declaración de declaración a la parte superior del alcance actual. Sin embargo, sólo las declaraciones activarán el levantamiento; las declaraciones de asignación (si las hay) permanecerán intactas. Expliquemoslo con algunos ejemplos.

// 用 var 声明得到提升
console.log(foo); // undefined
var foo = 1;
console.log(foo); // 1

// 用 let/const 声明不会提升
console.log(bar); // ReferenceError: bar is not defined
let bar = 2;
console.log(bar); // 2

Las declaraciones de funciones elevan el cuerpo de la función, pero las expresiones de funciones (escritas en forma de declaraciones de variables) solo tienen declaraciones de variables elevadas.

// 函数声明
console.log(foo); // [Function: foo]
foo(); // 'FOOOOO'
function foo() {
  console.log('FOOOOO');
}
console.log(foo); // [Function: foo]

// 函数表达式
console.log(bar); // undefined
bar(); // Uncaught TypeError: bar is not a function
var bar = function () {
  console.log('BARRRR');
};
console.log(bar); // [Function: bar]

Describa el evento burbujeante.

Cuando un evento se activa en un elemento DOM, si hay un detector de eventos, intentará manejar el evento y luego el evento se propaga a su elemento principal y sucede lo mismo. Finalmente hasta que el evento llegue al elemento ancestro. La propagación de eventos es el principio de implementar la delegación de eventos (delegación de eventos).

y¿Cuál es la diferencia entre =

==es un operador de igualdad abstracto, mientras que ===es un operador de igualdad estricto. ==El operador realiza las conversiones de tipos necesarias antes de la comparación. ===El operador no realiza conversión de tipo, por lo que si los dos valores no son del mismo tipo, se devuelven directamente false. Al utilizar ==, pueden suceder algunas cosas especiales, como por ejemplo:

1 == '1'; // true
1 == [1]; // true
1 == true; // true
0 == ''; // true
0 == '0'; // true
0 == false; // true

Mi consejo es nunca usar ==el operador excepto por conveniencia al comparar con nullor , si es o regresaráundefineda == nullanullundefinedtrue

var a = null;
console.log(a == null); // true
console.log(a == undefined); // true

Explique la política del mismo origen de JavaScript.

La política del mismo origen evita que JavaScript realice solicitudes de orígenes cruzados. Una fuente se define como una combinación de URI, nombre de host y número de puerto. Esta política evita que scripts maliciosos en una página accedan a datos confidenciales en otra página web a través del modelo de objetos de documento de la página.

¿Qué tan familiarizado estás con Promises y sus polyfills?

Entiende cómo funciona. PromiseEs un objeto que puede producir un resultado en algún momento en el futuro: el resultado de una operación exitosa o el motivo de su falla (por ejemplo, ocurrió un error de red). PromisePuede estar en uno de tres estados: fulfilled, rejectedo pending. Los usuarios pueden Promiseagregar funciones de devolución de llamada para manejar los resultados de operaciones exitosas o los motivos del fracaso.

Algunos más comunes polyfillson Polyfill $.deferred, Q y Bluebird, pero no todos los polyfills cumplen con la especificación. ES2015 admite promesas y los polirellenos generalmente no son necesarios ahora.

¿Cuáles son las ventajas y desventajas de Promise en lugar de la función de devolución de llamada?

ventaja

  • Evite el infierno de devoluciones de llamadas ilegibles.
  • El código asincrónico secuencial escrito usando .then() es simple y fácil de leer.
  • Escribir código asincrónico paralelo se vuelve fácil con Promise.all().

defecto

  • Aumenta ligeramente la complejidad del código (esto es discutible).
  • En navegadores más antiguos que no son compatibles con ES2015, es necesario introducir un polyfill para usarlo.

Explique la diferencia entre funciones sincrónicas y asincrónicas.

Las funciones síncronas se bloquean, mientras que las funciones asíncronas no se bloquean. En una función síncrona, una vez completada la declaración, se ejecuta la siguiente declaración. En este caso, el programa se puede evaluar exactamente en el orden de las declaraciones, y si una de las declaraciones tarda mucho tiempo, la ejecución del programa se detendrá durante mucho tiempo.

Las funciones asincrónicas generalmente aceptan una devolución de llamada como parámetro y continúan la ejecución en la siguiente línea inmediatamente después de llamar a la función asincrónica. La función de devolución de llamada solo se llama cuando se completa la operación asincrónica y la pila de llamadas está vacía. Las operaciones de carga pesada, como cargar datos desde un servidor web o consultar una base de datos, deben completarse de forma asincrónica para que el hilo principal pueda continuar realizando otras operaciones sin bloquearse hasta que se complete la operación que requiere mucho tiempo (en el navegador, la interfaz se congelará).

¿Qué es un bucle de eventos? ¿Cuál es la diferencia entre pila de llamadas y cola de tareas?

El bucle de eventos es un bucle de un solo subproceso que monitorea la pila de llamadas y verifica si algún trabajo está a punto de completarse en la cola de tareas. Si la pila de llamadas está vacía y hay una función de devolución de llamada en la cola de tareas, la función de devolución de llamada se retira de la cola y se inserta en la pila de llamadas para su ejecución.

¿Cuál es la diferencia entre crear variables usando let, var y const?

El alcance de una variable declarada vares su contexto de ejecución actual, que puede ser una función anidada o una variable declarada fuera de cualquier función. lety consttienen alcance de bloque, lo que significa que solo se puede acceder a ellos dentro del conjunto de llaves más cercano (en una función, bloque if-else o bucle for).

function foo() {
  // 所有变量在函数中都可访问
  var bar = 'bar';
  let baz = 'baz';
  const qux = 'qux';

  console.log(bar); // bar
  console.log(baz); // baz
  console.log(qux); // qux
}

console.log(bar); // ReferenceError: bar is not defined
console.log(baz); // ReferenceError: baz is not defined
console.log(qux); // ReferenceError: qux is not defined
if (true) {
  var bar = 'bar';
  let baz = 'baz';
  const qux = 'qux';
}

// 用 var 声明的变量在函数作用域上都可访问
console.log(bar); // bar
// let 和 const 定义的变量在它们被定义的语句块之外不可访问
console.log(baz); // ReferenceError: baz is not defined
console.log(qux); // ReferenceError: qux is not defined

varElevará la variable, lo que significa que la variable se puede usar antes de declararla. lety constno promoverá la variable, y se informará un error si se usa con anticipación.

console.log(foo); // undefined

var foo = 'foo';

console.log(baz); // ReferenceError: can't access lexical declaration 'baz' before initialization

let baz = 'baz';

console.log(bar); // ReferenceError: can't access lexical declaration 'bar' before initialization

const bar = 'bar';

Repetir varla declaración con no provocará un error, pero letcon y sí constlo hará.

var foo = 'foo';
var foo = 'bar';
console.log(foo); // "bar"

let baz = 'baz';
let baz = 'qux'; // Uncaught SyntaxError: Identifier 'baz' has already been declared

letconstLa diferencia entre y es que letse permiten varias asignaciones, mientras que constsolo se permite una.

// 这样不会报错。
let foo = 'foo';
foo = 'bar';

// 这样会报错。
const baz = 'baz';
baz = 'qux';

¿Puedes dar un ejemplo del uso de una función de flecha y en qué se diferencia de otras funciones?

Una ventaja obvia es que las funciones de flecha pueden simplificar la sintaxis de la creación de funciones y no necesitamos agregar functionpalabras clave delante de las funciones de flecha. Y la función de flecha thisse vinculará automáticamente al contexto del alcance actual, que es diferente de las funciones ordinarias. El valor de una función normal thissólo se puede determinar cuando se ejecuta. Esta característica de las funciones de flecha es particularmente útil para funciones de devolución de llamada, especialmente para Reactcomponentes.

¿Cuál es la definición de función de orden superior?

Una función de orden superior es una función que toma una o más funciones como parámetros, se utiliza para el procesamiento de datos y también puede devolver una función como resultado. Las funciones de orden superior se utilizan para abstraer operaciones repetitivas. Un ejemplo típico es mapque toma una matriz y una función como argumentos. mapUtilice esta función para convertir cada elemento en una matriz y devolver una nueva matriz que contenga los elementos convertidos. Otros ejemplos comunes en JavaScript son forEachy filter. reduceLas funciones de orden superior no solo se utilizan cuando es necesario operar matrices, sino que también hay muchos casos de uso en los que las funciones devuelven nuevas funciones. Function.prototype.bindSólo un ejemplo.

Ejemplo de mapa

Supongamos que tenemos una serie de nombres y necesitamos convertir cada carácter a mayúsculas.

const names = ['irish', 'daisy', 'anna'];

El método sin utilizar funciones de orden superior es este:

const transformNamesToUppercase = function (names) {
  const results = [];
  for (let i = 0; i < names.length; i++) {
    results.push(names[i].toUpperCase());
  }
  return results;
};
transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']

Úselo .map(transformerFn)para hacer que su código sea más conciso

const transformNamesToUppercase = function (names) {
  return names.map((name) => name.toUpperCase());
};
transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']

Dé un ejemplo de cómo desestructurar un objeto o matriz.

La desestructuración es una nueva característica de ES6, que proporciona una forma concisa y conveniente de extraer los valores de un objeto o matriz y colocarlos en diferentes variables.

desestructuración de matrices

// 变量赋值
const foo = ['one', 'two', 'three'];

const [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"
// 变量交换
let a = 1;
let b = 3;

[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1

Desestructuración de objetos

// 变量赋值
const o = {p: 42, q: true};
const {p, q} = o;

console.log(p); // 42
console.log(q); // true

¿Puedes dar un ejemplo de una función de curry? ¿Cuáles son sus beneficios?

Currying es un patrón en el que una función con múltiples argumentos se divide en múltiples funciones que, cuando se llaman en serie, acumulan todos los argumentos requeridos uno a la vez. Esta técnica ayuda a escribir código de estilo funcional, haciendo que el código sea más legible y compacto. Vale la pena señalar que para que una función sea curry, debe comenzar con una función y luego dividirla en una serie de funciones, cada una de las cuales toma un parámetro.

function curry(fn) {
  if (fn.length === 0) {
    return fn;
  }

  function _curried(depth, args) {
    return function (newArgument) {
      if (depth - 1 === 0) {
        return fn(...args, newArgument);
      }
      return _curried(depth - 1, [...args, newArgument]);
    };
  }

  return _curried(fn.length, []);
}

function add(a, b) {
  return a + b;
}

var curriedAdd = curry(add);
var addFive = curriedAdd(5);

var result = [0, 1, 2, 3, 4, 5].map(addFive); // [5, 6, 7, 8, 9, 10]

Supongo que te gusta

Origin blog.csdn.net/weixin_42439919/article/details/133065999
Recomendado
Clasificación