Preguntas y respuestas de la entrevista inicial de 2023


Entrevistador de tipos de datos JS
: ¿Qué son los tipos de datos básicos y los tipos de datos de referencia en JavaScript? ¿Y cómo se almacena cada tipo de datos? ⭐⭐⭐⭐⭐

Respuesta:
Los tipos de datos básicos son

Número
Cadena
Booleano
Nulo Símbolo
indefinido
(nuevo tipo de datos ES6) El tipo de datos de referencia
bigInt
se denomina colectivamente tipo de objeto. Si se subdivide, hay

Matriz de objetos
Fecha
Función RegExp Los datos del tipo de datos básicos se almacenan directamente en la pila, mientras que los datos del tipo de datos de referencia se almacenan en el montón y la dirección de referencia de los datos se guarda en la pila. Esta dirección de referencia
apunta a los datos correspondientes para que puedan ser encontrados rápidamente Objetos en la memoria del montón.

Por cierto, la memoria de la pila se asigna automáticamente. La memoria del montón se asigna dinámicamente y no se liberará automáticamente. Entonces, cada vez que termines de usar el objeto, configúralo en nulo para reducir el consumo de memoria inútil.

Conversión de tipo
Entrevistador: ¿Por qué 0,2+0,1>0,3 en JS?⭐⭐⭐⭐

respuesta:

Porque en JS, los números de coma flotante están representados por una longitud fija de 64 bits, de los cuales 1 bit representa el bit de signo, 11 bits se usan para representar el bit exponente y los 52 bits restantes son bits de mantisa, porque solo 52 bits representan el bit de mantisa.

La conversión de 0,1 a binario es un número de bucle infinito 0,0001100110011001100...(1100 bucles)

Método de conversión de decimal a binario desde decimal: https://jingyan.baidu.com/article/425e69e6e93ca9be15fc1626.html
Debes saber que el método de conversión de decimal a binario desde decimal es diferente al de entero, se recomienda tomar un mirar.

Dado que solo se pueden almacenar 52 bits de mantisa, habrá una pérdida de precisión. Si lo almacena en la memoria y luego lo saca y lo convierte a decimal, no será el 0,1 original, sino que se convertirá en 0,1000000000000000005551115123126, y por qué 02. +0.1 es porque

// Convierte 0.1 y 0.2 a binario antes de realizar la operación
0.00011001100110011001100110011001100110011001100110011010 +
0.0011001100110011001100110011001100110011 0 01100110011010 =
0,0100110011001100110011001100110011001100110011001100111

// Convertido a decimal, es exactamente 0,30000000000000004

Entrevistador: Entonces ¿por qué 0,2+0,3=0,5?⭐⭐⭐⭐

// Convierte 0,2 y 0,3 a binario antes de calcular
0,001100110011001100110011001100110011001100110011001101 +
0,010011001100110011001100110011001100110011
00 11001101 = 0.10000000000000000000000000000000000000000000000000001 //La mantisa tiene más de 52 dígitos

//El valor real solo toma la mantisa de 52 bits, que se convierte en
0.1000000000000000000000000000000000000000000000000000 //0.5

Respuesta: 0,2 y 0,3 se convierten respectivamente a binario para el cálculo: en la memoria, sus mantisas son iguales a 52 bits, y su suma debe ser mayor que 52 bits, y su suma da como resultado que las primeras 52 mantisas sean todas 0. Después intercepción, es exactamente 0.10000000000000000000000000000000000000000000000000, que es 0.5

Entrevistador: Dado que 0.1 ya no es 0.1, ¿por qué sigue siendo 0.1 cuando console.log(0.1)?⭐⭐⭐

Respuesta: Durante console.log, el binario se convierte a decimal y el decimal se convierte a formato de cadena. La aproximación ocurre durante el proceso de conversión, por lo que lo que se imprime es una cadena de valor aproximado.

Entrevistador: Hay varias formas de determinar el tipo de datos ⭐⭐⭐⭐⭐

respuesta:

tipo de

Desventajas: el valor de typeof null es Objeto y es imposible saber si es nulo u Objeto
instancia de

Desventaja: solo se puede determinar si el objeto existe en la cadena de prototipo del
constructor del objeto de destino.

Objeto.prototipo.toString.call()

Uno de los mejores métodos básicos de detección de tipos Object.prototype.toString.call(); puede distinguir entre nulo, cadena,

booleano, número, indefinido, matriz, función, objeto, fecha, tipos de datos matemáticos.

Desventajas: no se puede subdividir en casos de fulano de tal

// -----------------------------------------typeof
typeof undefined // 'undefined' 
typeof '10' // 'String' 
typeof 10 // 'Number' 
typeof false // 'Boolean' 
typeof Symbol() // 'Symbol' 
typeof Function // ‘function' 
typeof null // ‘Object’ 
typeof [] // 'Object' 
typeof {} // 'Object'


// -----------------------------------------instanceof
function Foo() { }
var f1 = new Foo();
var d = new Number(1)


console.log(f1 instanceof Foo);// true
console.log(d instanceof Number); //true
console.log(123 instanceof Number); //false   -->不能判断字面量的基本数据类型


// -----------------------------------------constructor
var d = new Number(1)
var e = 1
function fn() {
  console.log("ming");
}
var date = new Date();
var arr = [1, 2, 3];
var reg = /[hbc]at/gi;

console.log(e.constructor);//ƒ Number() { [native code] }
console.log(e.constructor.name);//Number
console.log(fn.constructor.name) // Function 
console.log(date.constructor.name)// Date 
console.log(arr.constructor.name) // Array 
console.log(reg.constructor.name) // RegExp




//-----------------------------------------Object.prototype.toString.call()
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]" 
console.log(Object.prototype.toString.call(null)); // "[object Null]" 
console.log(Object.prototype.toString.call(123)); // "[object Number]" 
console.log(Object.prototype.toString.call("abc")); // "[object String]" 
console.log(Object.prototype.toString.call(true)); // "[object Boolean]" 


function fn() {
  console.log("ming");
}
var date = new Date();
var arr = [1, 2, 3];
var reg = /[hbc]at/gi;
console.log(Object.prototype.toString.call(fn));// "[object Function]" 
console.log(Object.prototype.toString.call(date));// "[object Date]" 
console.log(Object.prototype.toString.call(arr)); // "[object Array]"
console.log(Object.prototype.toString.call(reg));// "[object RegExp]"

instancia de principio⭐⭐⭐⭐⭐

El principio de instancia de es en realidad encontrar la
función de cadena prototipo del objeto de destino myInstance (L, R) {// L representa el lado izquierdo de instancia de, R representa el lado derecho
var RP = R.prototype
var LP = L. proto
while (true) { if (LP = = null) { return false } if(LP == RP) { return true } LP = LP.proto } } console.log(myInstance({},Object)); Entrevistador: ¿Por qué? tipo de nulo es Objeto⭐⭐⭐⭐










respuesta:

Porque en JavaScript, diferentes objetos se almacenan en binario. Si los primeros tres dígitos del número binario son todos 0, el sistema lo juzgará como un tipo de objeto. Si el número binario nulo es todo 0, naturalmente se juzgará. ser un Objeto.

Este error se deja en la primera versión de JavaScript. Ampliemos los otros cinco bits de identificación:

000 Objeto
1 Tipo entero
010 Tipo de doble precisión
100 Cadena
110 Tipo booleano

Entrevistador:y=¿Cuál es la diferencia?⭐⭐⭐⭐⭐

respuesta:

=== es igualdad en sentido estricto y comparará los tipos de datos y tamaños de valores en ambos lados.

Si los tipos de datos son diferentes, devuelve false.
Los tipos de datos son los mismos, pero los tamaños de los valores son diferentes. Devolver false
== no es igual en sentido estricto.

Ambos lados son del mismo tipo, compara tamaños.

Los dos lados son de diferentes tipos. Consulte la tabla a continuación para obtener más comparaciones.

Nulo == Indefinido ->verdadero
Cadena == Número ->Primero convierta Cadena en Número, luego compare el tamaño
Booleano == Número ->Ahora convierta Booleano en Número, luego compare
Objeto == Cadena, Número, Símbolo -> Objeto Convertir a tipo primitivo

Entrevistador: Llamada manuscrita, aplicar, vincular⭐⭐⭐⭐⭐

respuesta:

La idea principal para la implementación de call and apply es:
determinar si es una llamada a función. Si no es una llamada a función, se lanzará una excepción.
Llamar a la función a través de un nuevo objeto (contexto).
Crear un fn para el contexto y configúrelo como la función que necesita ser llamada.
Elimine el fn después de que se complete la llamada.
La idea de implementación de enlace
determina si es una llamada de función. Si no es una llamada de función, se lanzará una excepción. Función
de retorno
. Determine cómo se llama la función. Si sale algo nuevo,
se devolverá un objeto vacío. Sin embargo, el __proto__ de la instancia apunta al prototipo de _this
para completar la función curry llamando a
Array.prototype.slice.call() :

Function.prototype.myCall = function (context) {
  // 先判断调用myCall是不是一个函数
  // 这里的this就是调用myCall的
  if (typeof this !== 'function') {
    throw new TypeError("Not a Function")
  }

  // 不传参数默认为window
  context = context || window

  // 保存this
  context.fn = this

  // 保存参数
  let args = Array.from(arguments).slice(1)   //Array.from 把伪数组对象转为数组

  // 调用函数
  let result = context.fn(...args)

  delete context.fn

  return result

}

aplicar

Function.prototype.myApply = function (context) { // Determinar que esto no es una función if (typeof this!== “function”) { throw new TypeError(“No es una función”) }



  let result

  // 默认是window
  context = context || window

  // 保存this
  context.fn = this

  // 是否传参
  if (arguments[1]) {
    result = context.fn(...arguments[1])
  } else {
    result = context.fn()
  }
  delete context.fn

  return result
}

unir

Function.prototype.myBind = function(context){
  // 判断是否是一个函数
  if(typeof this !== "function") {
    throw new TypeError("Not a Function")
  }
  // 保存调用bind的函数
  const _this = this 
  // 保存参数
  const args = Array.prototype.slice.call(arguments,1)
  // 返回一个函数
  return function F () {
    // 判断是不是new出来的
    if(this instanceof F) {
      // 如果是new出来的
      // 返回一个空对象,且使创建出来的实例的__proto__指向_this的prototype,且完成函数柯里化
      return new _this(...args,...arguments)
    }else{
      // 如果不是new出来的改变this指向,且完成函数柯里化
      return _this.apply(context,args.concat(...arguments))
    }
  } 
}

Entrevistador: ¿Cuál es la diferencia entre objetos creados por literales y objetos creados por nuevos? ¿Qué se implementa dentro de nuevos? Escribe un nuevo⭐⭐⭐⭐⭐ a mano.

respuesta:

Literal:

Crear objetos con literales es más sencillo y fácil de leer,
no requiere análisis de alcance y es más rápido.
Dentro de novedades:

Cree un nuevo objeto
, haga que el __proto__ del nuevo objeto apunte al prototipo de la función original,
cambie este punto (apuntando al nuevo obj) y ejecute la función. El resultado de la ejecución se guarda como resultado para
determinar si el resultado de la La función de ejecución es nula o indefinida. Si es así, devuelve el nuevo objeto anterior, si no, devuelve el resultado
escrito a mano.

// 手写一个new
function myNew(fn, ...args) {
  // 创建一个空对象
  let obj = {}
  // 使空对象的隐式原型指向原函数的显式原型
  obj.__proto__ = fn.prototype
  // this指向obj
  let result = fn.apply(obj, args)
  // 返回
  return result instanceof Object ? result : obj
}

Entrevistador: ¿Cuál es la diferencia entre el objeto creado por el literal new y el objeto creado por Object.create(null)⭐⭐⭐

respuesta:

Los objetos creados por literales y nuevos heredarán los métodos y propiedades de Object, y sus prototipos implícitos apuntarán al prototipo explícito de Object.

El prototipo del objeto creado por Object.create (null) es nulo y, como parte superior de la cadena de prototipos, naturalmente no hereda los métodos y propiedades de Object.

Pila de ejecución y contexto de ejecución
Entrevistador: ¿Qué es el alcance y qué es la cadena de alcance? ⭐⭐⭐⭐

respuesta:

Especificar el rango utilizable de variables y funciones se llama alcance.
Cada función tiene una cadena de alcance. Cuando se busca una variable o función, es necesario buscar desde el alcance local hasta el alcance global. El conjunto de estos alcances se llama alcance. cadena. .
Entrevistador: ¿Qué es la pila de ejecución y cuál es el contexto de ejecución? ⭐⭐⭐⭐

respuesta:

El contexto de ejecución se divide en:

El contexto de ejecución global
crea un objeto de ventana global y estipula que esto apunta a la ventana. Al ejecutar js, se empuja al final de la pila y aparece cuando se cierra el navegador. Contexto de ejecución de función Cada vez que se llama a una función, Se crea un nuevo contexto de ejecución de función
para
su ejecución
. El contexto se divide en la fase de creación y la fase de ejecución
. La fase de creación: el entorno de la función creará objetos variables: objeto de argumentos (y asignará un valor), declaración de función (y asignará un valor ), declaración de variable (no asignar un valor), declaración de expresión de función (no asignar un valor); se determinará a lo que apunta; determinará el alcance. Fase de ejecución: asignación de variable, asignación de expresión de función,
convertir la programación de objeto variable en objeto activo
contexto de ejecución de evaluación.Pila
de ejecución:

En primer lugar, las características de la pila: primero en entrar, último en salir
. Al ingresar a un entorno de ejecución, su contexto de ejecución se creará y luego se insertará en la pila. Cuando se complete la ejecución del programa, su contexto de ejecución se destruirá y la pila se estalló.
La parte inferior de la pila es siempre el contexto de ejecución del entorno global, y la parte superior de la pila es siempre el contexto de ejecución de la función en ejecución. El contexto de ejecución global aparecerá
solo cuando el navegador esté cerrado. Cierres Muchas personas no pueden entender cierres js. Aquí se recomienda un artículo: Comprenda a fondo los cierres en js

Entrevistador: ¿Qué es un cierre? ¿Qué hace el cierre? ¿Aplicación de cierre? ⭐⭐⭐⭐⭐

respuesta:

La ejecución de funciones forma un contexto de ejecución privado para proteger las variables privadas internas de interferencias externas y desempeñar un papel en la protección y preservación.

efecto:

Protección
Evite conflictos de nombres
Guardar
Resolver problemas de índice causados ​​por el enlace circular
Las variables no serán destruidas
Puede usar variables dentro de funciones para que no sean recicladas por el mecanismo de recolección de basura
Aplicación:

Modo singleton en patrones de diseño
Preservar las operaciones i en bucles for
Antivibración y estrangulamiento
Curry de funciones
Desventajas

Habrá problemas de pérdida de memoria
Prototipo y cadena de prototipo
Entrevistador: ¿Qué es un prototipo? ¿Qué es una cadena prototipo? Cómo entender ⭐⭐⭐⭐⭐

respuesta:

Prototipo: El prototipo se divide en prototipo implícito y prototipo explícito, cada objeto tiene un prototipo implícito, que apunta al prototipo explícito de su propio constructor.

Cadena de prototipos: una colección de múltiples __proto__ se convierte en una cadena de prototipos

El __proto__ de todas las instancias apunta al prototipo de sus constructores.
Todos los prototipos son objetos. Naturalmente, su __proto__ apunta al prototipo de Object(). Los
prototipos implícitos de todos los constructores apuntan a Function().
El prototipo implícito del El objeto es
herencia nula
Entrevistador: ¿Cuáles son los métodos de herencia comunes en JS? Y las ventajas y desventajas de cada método de herencia. ⭐⭐⭐⭐⭐

respuesta:

Herencia prototípica, herencia combinada, herencia combinada parasitaria, extensión ES6

herencia prototípica

// ----------------------方法一:原型继承
// 原型继承
// 把父类的实例作为子类的原型
// 缺点:子类的实例共享了父类构造函数的引用属性   不能传参

var person = {
  friends: ["a", "b", "c", "d"]
}

var p1 = Object.create(person)

p1.friends.push("aaa")//缺点:子类的实例共享了父类构造函数的引用属性

console.log(p1);
console.log(person);//缺点:子类的实例共享了父类构造函数的引用属性

herencia compositiva

// ----------------------方法二:组合继承
// 在子函数中运行父函数,但是要利用call把this改变一下,
// 再在子函数的prototype里面new Father() ,使Father的原型中的方法也得到继承,最后改变Son的原型中的constructor

// 缺点:调用了两次父类的构造函数,造成了不必要的消耗,父类方法可以复用
// 优点可传参,不共享父类引用属性
function Father(name) {
  this.name = name
  this.hobby = ["篮球", "足球", "乒乓球"]
}

Father.prototype.getName = function () {
  console.log(this.name);
}

function Son(name, age) {
  Father.call(this, name)
  this.age = age
}

Son.prototype = new Father()
Son.prototype.constructor = Son


var s = new Son("ming", 20)

console.log(s);

herencia combinada parasitaria

// ----------------------方法三:寄生组合继承
function Father(name) {
  this.name = name
  this.hobby = ["篮球", "足球", "乒乓球"]
}

Father.prototype.getName = function () {
  console.log(this.name);
}

function Son(name, age) {
  Father.call(this, name)
  this.age = age
}

Son.prototype = Object.create(Father.prototype)
Son.prototype.constructor = Son

var s2 = new Son("ming", 18)
console.log(s2);

extender

// ----------------------方法四:ES6的extend(寄生组合继承的语法糖)
//     子类只要继承父类,可以不写 constructor ,一旦写了,则在 constructor 中的第一句话
// 必须是 super 。

class Son3 extends Father { // Son.prototype.__proto__ = Father.prototype
  constructor(y) {
    super(200)  // super(200) => Father.call(this,200)
    this.y = y
  }
}

Pérdida de memoria, mecanismo de recolección de basura
Entrevistador: ¿Qué es una pérdida de memoria?⭐⭐⭐⭐⭐

respuesta:

​ La pérdida de memoria significa que la memoria que ya no se usa no se libera a tiempo, lo que hace que la memoria quede inutilizable, lo que se denomina pérdida de memoria.

Entrevistador: ¿Por qué causa pérdida de memoria?⭐⭐⭐⭐⭐

respuesta:

Una pérdida de memoria significa que no podemos acceder a un objeto a través de js, pero el mecanismo de recolección de basura cree que todavía se hace referencia al objeto, por lo que el mecanismo de recolección de basura no liberará el objeto, lo que provocará que el bloque de memoria nunca se libere. Esta cantidad se suma a un gran problema en el sistema, que se atascará cada vez más e incluso colapsará.

Entrevistador: ¿Cuáles son las estrategias del mecanismo de recolección de basura? ⭐⭐⭐⭐⭐

respuesta:

El mecanismo de recolección de basura de marcar y barrer
obtiene las raíces y las marca, luego accede y marca todas las referencias de ellas, y luego accede a estos objetos y marca sus referencias... Al final de esta progresión, si hay alguna sin marcar (inalcanzable) se encuentran objetos, proceda a eliminar, no se pueden eliminar después de ingresar al entorno de ejecución.Método
de recuento de referencias:
cuando se declara una variable y se asigna un valor de tipo de referencia a la variable, el recuento del valor es +1.Cuando se asigna el valor a otra variable, el recuento es +1. Cuando el valor se reemplaza por otros valores, el recuento es -1. Cuando el recuento llega a 0, significa que no se puede acceder al valor y el mecanismo de recolección de basura borra el objeto. Desventajas: cuando dos objetos hacen referencia circularmente, el
recuento de referencias no se puede hacer nada. Si la referencia circular se ejecuta varias veces, causará problemas como fallas. Más tarde fue reemplazado por el método de marcar y barrer.
Copia profunda y copia superficial
Copia superficial manuscrita Copia profunda ⭐⭐⭐⭐⭐

// ----------------------------------------------浅拷贝
// 只是把对象的属性和属性值拷贝到另一个对象中
var obj1 = {
  a: {
    a1: { a2: 1 },
    a10: { a11: 123, a111: { a1111: 123123 } }
  },
  b: 123,
  c: "123"
}
// 方式1
function shallowClone1(o) {
  let obj = {}

  for (let i in o) {
    obj[i] = o[i]
  }
  return obj
}

// 方式2
var shallowObj2 = { ...obj1 }

// 方式3
var shallowObj3 = Object.assign({}, obj1)

let shallowObj = shallowClone1(obj1);

shallowObj.a.a1 = 999
shallowObj.b = true

console.log(obj1);  //第一层的没有被改变,一层以下就被改变了



// --------------

Supongo que te gusta

Origin blog.csdn.net/sinat_52319736/article/details/129244829
Recomendado
Clasificación