2023 front-end interview questions and answers

JS
Data Types
Interviewer: What are basic data types and reference data types in JavaScript? And how are each data type stored? ⭐⭐⭐⭐⭐

Answer:
The basic data types are

Number
String
Boolean
Null
Undefined
Symbol (ES6 new data type)
bigInt
reference data type is collectively called the Object type. If it is subdivided, there are

Object
Array
Date
Function
RegExp
The data of the basic data type is stored directly in the stack; while the data of the reference data type is stored in the heap, and the reference address of the data is saved in the stack. This reference address points to the corresponding data so that it can be quickly found. Objects in heap memory.

By the way, stack memory is allocated automatically. The heap memory is dynamically allocated and will not be automatically released. So every time you finish using the object, set it to null to reduce the consumption of useless memory.

Type conversion
Interviewer: Why 0.2+0.1>0.3 in JS?⭐⭐⭐⭐

answer:

Because in JS, floating point numbers are represented by a 64-bit fixed length, of which 1 bit represents the sign bit, 11 bits are used to represent the exponent bit, and the remaining 52 bits are mantissa bits, because only 52 bits represent the mantissa bit.

The conversion of 0.1 to binary is an infinite loop number 0.0001100110011001100...(1100 loops)

Method of converting decimal to binary from decimal: https://jingyan.baidu.com/article/425e69e6e93ca9be15fc1626.html
You should know that the method of converting decimal to binary from decimal is different from that of integer. It is recommended to take a look.

Since only 52 mantissa bits can be stored, there will be a loss of precision. If you store it in memory and then take it out and convert it to decimal, it will not be the original 0.1, but will become 0.100000000000000005551115123126, and why 02+0.1 is because

// Convert 0.1 and 0.2 into binary before performing the operation
0.00011001100110011001100110011001100110011001100110011010 +
0.0011001100110011001100110011001100110011 001100110011010 =
0.0100110011001100110011001100110011001100110011001100111

// Converted to decimal, it is exactly 0.30000000000000004

Interviewer: Then why 0.2+0.3=0.5?⭐⭐⭐⭐

// Convert 0.2 and 0.3 to binary before calculating
0.001100110011001100110011001100110011001100110011001101 +
0.010011001100110011001100110011001100110011
0011001101 = 0.1000000000000000000000000000000000000000000000000001 //The mantissa is greater than 52 digits

//The actual value only takes the 52-bit mantissa, which becomes
0.1000000000000000000000000000000000000000000000000000 //0.5

Answer: 0.2 and 0.3 are respectively converted to binary for calculation: in the memory, their mantissas are equal to 52 bits, and their sum must be greater than 52 bits, and their addition happens to have the first 52 mantissas all being 0. After interception, it is exactly 0.100000000000000000000000000000000000000000000000000, which is 0.5

Interviewer: Since 0.1 is no longer 0.1, why is it still 0.1 when console.log(0.1)?⭐⭐⭐

Answer: During console.log, binary is converted to decimal, and decimal is converted to string form. Approximation occurs during the conversion process, so what is printed is a string of approximate value.

Interviewer: There are several ways to determine the data type ⭐⭐⭐⭐⭐

answer:

typeof

Disadvantages: The value of typeof null is Object, and it is impossible to tell whether it is null or Object
instanceof

Disadvantage: Can only determine whether the object exists on the prototype chain of the target object
constructor

Object.prototype.toString.call()

One of the best basic type detection methods Object.prototype.toString.call(); it can distinguish between null, string,

boolean, number, undefined, array, function, object, date, math data types.

Disadvantages: cannot be subdivided into instances of so and so

// -----------------------------------------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]"

instanceof principle⭐⭐⭐⭐⭐

The principle of instanceof is actually to find the prototype chain
function of the target object myInstance(L, R) {//L represents the left side of instanceof, R represents the right side
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)); Interviewer: Why typeof null is Object⭐⭐⭐⭐










answer:

Because in JavaScript, different objects are stored in binary. If the first three digits of the binary number are all 0, the system will judge it to be an Object type. If the binary number of null is all 0, it will naturally be judged to be an Object.

This bug is left in the first version of JavaScript. Let’s expand the other five identification bits:

000 Object
1 Integer type
010 Double precision type
100 String
110 Boolean type

Interviewer:and=What’s the difference⭐⭐⭐⭐⭐

answer:

=== is equality in the strict sense and will compare the data types and value sizes on both sides.

If the data types are different, return false.
The data types are the same, but the value sizes are different. Returning false
== is not equal in the strict sense.

Both sides are of the same type, compare sizes

The two sides are of different types. Please refer to the table below for further comparison.

Null == Undefined ->true
String == Number ->First convert String to Number, then compare the size
Boolean == Number ->Now convert Boolean to Number, then compare
Object == String, Number, Symbol -> Object Convert to primitive type

Interviewer: Handwritten call, apply, bind⭐⭐⭐⭐⭐

answer:

The main idea for the implementation of call and apply is:
determine whether it is a function call. If it is not a function call, an exception will be thrown.
Call the function through a new object (context).
Create a fn for the context and set it as the function that needs to be called.
Delete the fn after the call is completed.
The bind implementation idea
determines whether It is a function call. If it is not a function call, an exception will be thrown.
Return
function. Determine how the function is called. If new comes out, an
empty object will be returned. However, the __proto__ of the instance points to the prototype of _this
to complete the function currying
Array.prototype. slice.call()
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

}

apply

Function.prototype.myApply = function (context) { // Determine this is not a function if (typeof this !== “function”) { throw new TypeError(“Not a Function”) }



  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
}

bind

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))
    }
  } 
}

Interviewer: What is the difference between objects created by literals and objects created by new? What is implemented inside new? Write a new⭐⭐⭐⭐⭐ by hand.

answer:

Literal:

Creating objects with literals is simpler and easier to read.
It does not require scope analysis and is faster.
Inside new:

Create a new object
, make the __proto__ of the new object point to the prototype of the original function,
change this point (pointing to the new obj) and execute the function. The execution result is saved as result to
determine whether the result of the execution function is null or Undefined. If so, then Return the previous new object, if not, return result
handwritten new

// 手写一个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
}

Interviewer: What is the difference between the object created by the literal new and the object created by Object.create(null)⭐⭐⭐

answer:

Objects created by literals and new will inherit the methods and properties of Object, and their implicit prototypes will point to the explicit prototype of Object.

The prototype of the object created by Object.create(null) is null. As the top of the prototype chain, it naturally does not inherit the methods and properties of Object.

Execution stack and execution context
Interviewer: What is scope and what is scope chain? ⭐⭐⭐⭐

answer:

Specifying the usable range of variables and functions is called a scope.
Each function has a scope chain. When looking for a variable or function, you need to search from the local scope to the global scope. The set of these scopes is called the scope chain. .
Interviewer: What is the execution stack and what is the execution context? ⭐⭐⭐⭐

answer:

The execution context is divided into:

Global execution context
creates a global window object and stipulates that this points to the window. When executing js, it is pushed to the bottom of the stack and pops up when the browser is closed. Function execution context Each time a function is called, a new function execution context is created
for
execution
. The context is divided into the creation phase and the execution phase
. The creation phase: the function environment will create variable objects: arguments object (and assign a value), function declaration (and assign a value), variable declaration (not assign a value), function expression declaration (not assign a value); will be determined this points to; it will determine the scope.
Execution phase: variable assignment, function expression assignment, making variable object programming active object
eval execution context.
Execution stack:

First of all, stack characteristics: first in, last out.
When entering an execution environment, its execution context will be created and then pushed onto the stack. When the program execution is completed, its execution context will be destroyed and the stack will be popped.
The bottom of the stack is always the execution context of the global environment, and the top of the stack is always the execution context of the executing function. The global execution context will pop up
only when the browser is closed. Closures Many people cannot understand js closures. Here is an article recommended: Thoroughly understand closures in js

Interviewer: What is a closure? What does closure do? Application of closure? ⭐⭐⭐⭐⭐

answer:

Function execution forms a private execution context to protect internal private variables from external interference and play a role in protection and preservation.

effect:

Protection
Avoid naming conflicts
Save
Solve index problems caused by circular binding
Variables will not be destroyed
You can use variables inside functions so that they will not be recycled by the garbage collection mechanism
Application:

Singleton mode in design patterns
Preserving i operations in for loops
Anti-shake and throttling
Function currying
Disadvantages

There will be memory leak problems.
Prototype and prototype chain.
Interviewer: What is a prototype? What is a prototype chain? How to understand ⭐⭐⭐⭐⭐

answer:

Prototype: Prototype is divided into implicit prototype and explicit prototype. Each object has an implicit prototype, which points to the explicit prototype of its own constructor.

Prototype chain: A collection of multiple __proto__ becomes a prototype chain

The __proto__ of all instances point to the prototype of their constructors.
All prototypes are objects. Naturally, its __proto__ points to the prototype of Object(). The
implicit prototypes of all constructors point to Function().
The implicit prototype of the displayed prototype Object is null
inheritance.
Interviewer: What are the common inheritance methods in JS? And the advantages and disadvantages of each inheritance method. ⭐⭐⭐⭐⭐

answer:

Prototypal inheritance, combined inheritance, parasitic combined inheritance, ES6 extend

prototypal inheritance

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

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

var p1 = Object.create(person)

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

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

compositional inheritance

// ----------------------方法二:组合继承
// 在子函数中运行父函数,但是要利用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);

parasitic combination inheritance

// ----------------------方法三:寄生组合继承
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);

extend

// ----------------------方法四: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
  }
}

Memory leak, garbage collection mechanism
Interviewer: What is a memory leak⭐⭐⭐⭐⭐

answer:

​ Memory leak means that the memory that is no longer used is not released in time, causing the memory to be unusable. This is a memory leak.

Interviewer: Why does it cause memory leak⭐⭐⭐⭐⭐

answer:

A memory leak means that we cannot access an object through js, but the garbage collection mechanism thinks that the object is still being referenced, so the garbage collection mechanism will not release the object, causing the block of memory to never be released. A small amount adds up to a big problem in the system. It will become more and more stuck and even collapse.

Interviewer: What are the strategies for the garbage collection mechanism? ⭐⭐⭐⭐⭐

answer:

The mark-and-sweep
garbage collection mechanism obtains the roots and marks them, then accesses and marks all references from them, and then accesses these objects and marks their references... At the end of this progression, if any unmarked (unreachable) objects are found, proceed Delete, cannot be deleted after entering the execution environment.
Reference counting method:
When a variable is declared and a reference type value is assigned to the variable, the count of the value is +1. When the value is assigned to another variable, the count is +1. , when the value is replaced by other values, the count is -1. When the count becomes 0, it means that the value cannot be accessed, and the garbage collection mechanism clears the object. Disadvantages: When two objects reference circularly, the reference
count Nothing can be done. If the circular reference is executed multiple times, it will cause problems such as crashes. So it was later replaced by the mark-and-sweep method.
Deep copy and shallow copy
Handwritten shallow copy Deep copy ⭐⭐⭐⭐⭐

// ----------------------------------------------浅拷贝
// 只是把对象的属性和属性值拷贝到另一个对象中
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);  //第一层的没有被改变,一层以下就被改变了



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

Guess you like

Origin blog.csdn.net/sinat_52319736/article/details/129244829