LMX
BlogSelectedWorkSponsorsAbout
Command Palette

Search for a command to run...

Blog

Intermediate Front-End Interview Compilation - Middle Volume

LMXMar 5, 202417 min read#Interview Summary

Summarized some common knowledge points and questions in intermediate front-end interviews, covering topics such as the event loop, on-demand loading in Webpack and Vite, HTTP cache control strategies, and the differences between Vue2 and Vue3.

Basic Types in JS

The basic types in JavaScript refer to: those value types stored in memory. They are immutable, which means that once created, the value type cannot be changed.

7 Basic Types in JS

  • Boolean: Represents true or false
  • Number: Represents integers, floats, or NaN
  • String: Represents a string of characters
  • Null: Represents an empty value
  • Undefined: Represents a variable that has not been assigned a value
  • Symbol: Represents a unique value (added in ES6)
  • BigInt: Represents an integer of arbitrary precision (added in ES11)

Detailed Introduction

Boolean

Boolean values are only two: true or false. They are usually used to represent conditions or switches.

For example:

const isLoggedIn = true;

if (isLoggedIn) {
  // 用户已登录
} else {
  // 用户未登录
}

Number

A number can be an integer, a floating-point number, or NaN.

  • Integer: for example, 1, 2, 3, etc.
  • Floating-point number: for example, 1.2, 3.14, -0.5, etc.
  • NaN: represents a non-numeric value.

For example:

const age = 25;
const pi = 3.14;
const invalidNumber = NaN;

console.log(age + pi); // 28.14
console.log(invalidNumber / 2); // NaN

String

A string is a collection of characters. They can be enclosed in single quotes, double quotes, or backticks.

For example:

const name = "John Doe";
const message = "Hello, world!";
const multilineString = `This is a
multiline string.`;

console.log(name + " says " + message); // John Doe says Hello, world!
console.log(multilineString);

Null

A null value represents an empty value. It is different from undefined, which indicates that a variable has not been assigned a value.

For example:

const variable = null;

console.log(variable === undefined); // false
console.log(variable === null); // true

Undefined

Undefined indicates that a variable has not been assigned a value.

For example:

let variable;

console.log(variable); // undefined

Symbol

Symbol is a new data type introduced in ES6, which represents a unique value. Symbol values are usually used to represent object property keys or private members.

For example:

const symbol1 = Symbol();
const symbol2 = Symbol();

console.log(symbol1 === symbol2); // false

const object = {
  [symbol1]: "Hello",
  [symbol2]: "World",
};

console.log(object[symbol1]); // Hello
console.log(object[symbol2]); // World

BigInt

BigInt is a new data type introduced in ES2020 (ES11). It represents an integer of arbitrary precision.

For example:

const bigInt = 12345678901234567890n;

console.log(bigInt.toString()); // 12345678901234567890

BigInt Extensions

BigInt is a primitive type in JavaScript used to represent integers of arbitrary precision. It can represent integer values beyond the range that the Number type can represent, that is, integers beyond ±(2^53-1) (i.e., Number.MAX_SAFE_INTEGER). BigInt was introduced as a new feature in ECMAScript 2020 (ES11).

BigInt can be created by adding the n suffix to a number, for example:

const bigIntNumber = 1234567890123456789012345678901234567890n;

In this example, 1234567890123456789012345678901234567890n is an integer of type BigInt.

Since the integers represented by BigInt have no range limits, they can be used for operations on large integers, such as in encryption algorithms, numerical computations, and other fields.

Although BigInt is similar to the Number type, they are not completely compatible with each other. BigInt cannot be directly mixed with Number in operations and needs to be manipulated using BigInt methods and operators. Additionally, BigInt does not support the methods on the Number object.

The operations and operators supported by BigInt include addition (+), subtraction (-), multiplication (*), division (/), remainder (%), and comparison operators (<, >, <=, >=, ==, !=, ===, !==). Additionally, BigInt provides some methods for operations and conversions, such as BigInt.asIntN(), BigInt.asUintN(), etc.

It should be noted that since BigInt is a new feature introduced in ES11, it may not be supported in some older browsers. When using BigInt, you should ensure that your runtime environment supports this feature, or use an appropriate polyfill or transpilation tool for compatibility handling.

Reference Types in JS

In JavaScript, reference types refer to objects stored in heap memory, which are mutable, meaning that once created, their values can be changed.

Common Reference Types in JS:

  • Object
  • Array
  • Function
  • Date
  • RegExp
  • Error
  • Other built-in objects

Detailed Introduction

Object

An object is the most basic reference type in JavaScript. It is an unordered collection composed of key-value pairs. The keys of an object are strings, and the values can be any type of data, including primitive types and other reference types.

For example:

const person = {
  name: "John Doe",
  age: 25,
  address: {
    city: "New York",
    state: "NY",
    zip: "10001",
  },
};

Array

An array is a special type of object used to store an ordered collection of data. Each element of an array can be any type of data, including primitive types and other reference types.

For example:

const numbers = [1, 2, 3, 4, 5];
const fruits = ["apple", "banana", "orange"];

Function

A function is a special kind of object that can be called to execute code. A function can accept parameters and return values, and it can also be used as an object's property and method.

For example:

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

const result = add(1, 2); // 3

Date

The Date type is used to represent dates and times. It is a built-in object in JavaScript and can be used to create instances representing specific dates and times.

For example:

const date = new Date();
console.log(date.toString()); // "Thu Feb 16 2023 20:07:12 GMT+0800 (中国标准时间)"

Regular Expressions (RegExp)

Regular expressions are objects used to match string patterns. They can be used to search, replace, and extract specific parts of a string.

For example:

const regex = /\d+/g;
const matches = regex.exec("The answer is 42"); // ["42"]

Error (Errror)

The error object represents an error that occurs during program execution.

For example:

try {
  // 这里可能会发生错误
} catch (error) {
  // 处理错误
}

The Particularity of Reference Types in JS

  • Reference: The value of a reference type is passed by reference. This means that assigning a reference type actually copies the reference to the object, rather than copying the object itself.
  • Mutability: The value of a reference type can be changed. Changes to the properties of a reference type will affect all variables that reference the object.
  • Prototype: Each reference type has a prototype object, which contains all the default properties and methods of that type.

Differences Between Arrow Functions and Regular Functions

The differences between arrow functions and regular functions mainly include five aspects: syntax, this binding, arguments object, constructor, and prototype.

  • Syntax:

    Arrow functions are defined using "=>", while regular functions are defined using the function keyword.

    For example:

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

const add = (a, b) => a + b;
  • this binding:

    The this in an arrow function always refers to the context object where it was defined, whereas the this in a regular function changes depending on how the function is called.

    For example:

const obj = {
  name: "obj",
  add: function (a, b) {
    console.log(this.name);
    return a + b;
  },
};

const add = (a, b) => {
  console.log(this.name);
  return a + b;
};

obj.add(1, 2); // 'obj'
add(1, 2); // undefined
  • arguments object:

    Arrow functions do not have an arguments object, whereas in regular functions you can access the function's parameter list through the arguments object.

For example:

const add = function (a, b) {
  console.log(arguments);
  return a + b;
};

const add = (a, b) => {
  console.log(arguments); // ReferenceError: arguments is not defined
  return a + b;
};

add(1, 2);
  • Constructor:

    Arrow functions cannot be used as constructors, whereas regular functions can.

    For example:

const Person = function (name) {
  this.name = name;
};

const Person = () => {
  this.name = name;
};

const person = new Person("John"); // TypeError: Arrow functions cannot be used as constructors
  • prototype property:

    Arrow functions do not have a prototype property, whereas regular functions can use the prototype property to add methods to the function. For example:

const Person = function (name) {
  this.name = name;
};

Person.prototype.sayHello = function () {
  console.log(`Hello, my name is ${this.name}`);
};

const person = new Person("John");
person.sayHello(); // 'Hello, my name is John'

const Person = () => {
  this.name = name;
};

const person = new Person("John");
person.sayHello(); // TypeError: person.sayHello is not a function

In summary, arrow functions and regular functions each have their advantages and disadvantages. Arrow functions have a more concise syntax and a more explicit this binding, but they cannot be used as constructors, do not have a prototype property, and cannot use the yield command. Regular functions are more powerful, but their syntax is more cumbersome, and the this binding is easy to confuse. In practical development, the appropriate function definition method should be chosen according to specific needs.

Difference Between Deep Copy and Shallow Copy

Shallow copy and deep copy are two common ways of copying objects. The main difference is that shallow copy only copies the reference of the object, while deep copy copies the entire value of the object, including all properties and sub-objects.

Shallow Copy

Shallow copy means assigning the reference of an object to another object, which means that the two objects will point to the same memory address. If you modify a property of one object, the property of the other object will also change.

Deep Copy

Deep copy means creating a new object and copying all its properties and sub-object values into the new object. This means that the two objects have completely different memory addresses and do not affect each other.

Difference Between Shallow Copy and Deep Copy

DifferenceShallow CopyDeep Copy
Copy MethodCopy referenceCopy value
Memory AddressSameDifferent
Modification EffectAffect each otherDo not affect each other

For example:

// 原对象
const originalObj = {
  name: "John",
  age: 30,
  hobbies: ["reading", "music"],
};

// 浅拷贝
const shallowCopyObj = Object.assign({}, originalObj);
shallowCopyObj.hobbies.push("sports");

console.log(originalObj.hobbies); // ['reading', 'music', 'sports']
console.log(shallowCopyObj.hobbies); // ['reading', 'music', 'sports']

// 深拷贝
const deepCopyObj = JSON.parse(JSON.stringify(originalObj));
deepCopyObj.hobbies.push("drawing");

console.log(originalObj.hobbies); // ['reading', 'music', 'sports']
console.log(deepCopyObj.hobbies); // ['reading', 'music', 'drawing']

How to Implement Deep Copy

In JavaScript, deep copy can be achieved in the following ways:

  • Using JSON.parse() and JSON.stringify() methods
  • Using recursive functions
  • Using third-party libraries

JSON.parse() and JSON.stringify() Methods

The JSON.parse() and JSON.stringify() methods can convert an object into a JSON string, and then parse the JSON string back into an object. This method can achieve deep copy, but it should be noted that it will ignore the object's prototype and circular references.

Recursive Functions

Using recursive functions can achieve deep copy. Recursive functions traverse each property of the object and copy its value to a new object. This method can achieve deep copy, but it should be noted that it may call recursively, leading to performance issues.

For example:

function deepCopy(obj, visited = new WeakMap()) {
  // 基本类型或 null,直接返回
  if (typeof obj !== "object" || obj === null) return obj;

  // 如果已拷贝的对象则直接进行返回
  if (visited.has(obj)) return visited.get(obj);

  // 对日期类型和正则表达式进行特殊处理,直接复制构造函数
  if (obj instanceof Date || obj instanceof RegExp)
    return new obj.constructor(obj);

  let copy = Array.isArray(obj) ? [] : {}; // 创建目标对象

  visited.set(obj, copy); // 记录已拷贝的对象

  for (let key in obj) {
    // 遍历对象的属性
    // 只复制自身属性,非原型链上的属性
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      copy[key] = deepCopy(obj[key], visited); // 递归拷贝
    }
  }

  return copy;
}

Third-Party Libraries

You can use third-party libraries to implement deep cloning. For example, Underscore.js and Lodash both provide methods for deep cloning.

Differences Between Class Components and Functional Components

In React, there are two ways to create components: one is class components, and the other is functional components. Class components are created using ES6 classes, while functional components are created using JavaScript functions.

Class Components

Created using ES6 classes and extend the React.Component class. They also have the following characteristics:

  • Have a lifecycle
  • Can use state
  • Can use the 'this' keyword to access the component instance

Functional Components

Functional components are a newer type of component in React, introduced in React 16.8. They are created using JavaScript functions but do not have lifecycle methods or state.

  • No lifecycle
  • No state
  • Cannot use 'this' to access the component instance

Differences Between Class Components and Functional Components

The following are the main differences between class components and functional components:

FeatureClass ComponentFunctional Component
CreationUsing ES6 classUsing JavaScript function
InheritanceInherits from React.Component classNone
LifecycleHas lifecycle methodsNo lifecycle methods
StatusUsable StatusUnusable Status
this KeywordCan use this keyword to access component instanceCannot use this keyword to access component instance
PerformanceSlightly worse performanceSlightly better performance
ReadabilitySlightly worse readabilitySlightly better readability

Choosing Between Class Components and Functional Components

The following factors should be considered:

  • Whether the component needs state
  • Whether the component needs lifecycle methods
  • The complexity of the component
  • Code readability

Understanding Closures

In JS, a closure refers to a function being able to access variables in the scope of its outer function. In other words, closures allow functions to remember the environment in which they were created.

Formation of Closures

Closures are formed when one function is defined inside another function; the inner function can access variables in the outer function's scope, even if the outer function has already finished executing.

Example of a Closure

function outer() {
  let count = 0;

  function inner() {
    count++;
    console.log(count);
  }
  return inner;
}

const fn = outer();

fn(); // 1
fn(); // 2

console.log(count); // undefined

In this example, the inner function is a closure, which can access the variable count in the outer function outer. Even after the outer function has finished executing, the inner function can still access the count variable.

Advantages of Closures

  • Can encapsulate code, improving code reusability
  • Can implement private variables, enhancing code security
  • Can simulate classes in object-oriented programming

Disadvantages of Closures

  • May cause memory leaks
  • May make code harder to understand

Use Cases of Closures

  • Implementing delayed execution

    function delay(fn, delay) {
      return setTimeout(fn, delay);
    }
    
    const fn = () => console.log("Hello");
    
    delay(fn, 1000); // Outputs "Hello" after 1 second
  • Simulating classes in object-oriented programming

    function Person(name) {
      this.name = name;
    
      const sayHello = () => console.log(`Hello, my name is ${this.name}`);
    
      return {
        sayHello,
      };
    }
    
    const person = new Person("John Doe");
    
    person.sayHello(); // Outputs "Hello, my name is John Doe"
  • Creating private variables

    function counter() {
      let count = 0;
    
      function increment() {
        count++;
      }
      function getCount() {
        return count;
      }
    
      return {
        increment,
        getCount,
      };
    }
    
    const counter = counter();
    
    counter.increment();
    counter.increment();
    
    console.log(counter.getCount()); // 2
  • Implement event listening

    function addEventListener(element, type, listener) {
      element.addEventListener(type, listener);
    
      return () => element.removeEventListener(type, listener);
    }
    
    const element = document.getElementById("button");
    
    const removeListener = addEventListener(element, "click", () =>
      console.log("Button clicked"),
    );
    
    // Remove event listener
    removeListener();

Detailed Explanation of Promise

Promise is an object introduced in ES6 for handling asynchronous operations. It represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

Promise States

  • Pending: Initial state, indicating the asynchronous operation is not yet completed and is in progress.
  • Fulfilled: Indicates the asynchronous operation has completed.
  • Rejected: Indicates the asynchronous operation has failed.

Promise State Changes

The state of a Promise can only be changed by resolve and reject.

  • The resolve function changes the state of the Promise to Fulfilled and passes a result as the value.
  • The reject function changes the state of the Promise to Rejected and passes an error object as the reason.

Once the Promise state changes, it cannot be reversed!

Examples of Promise states:

const promise = new Promise((resolve, reject) => {
  setTimeOut(() => {
    resolve("success");
  }, 1000);
});

promise.then(
  (reslut) => {
    console.log(reslut); // 'success'
  },
  (error) => {
    console.log(error);
  },
);

In this example, the initial state of the Promise is Pending. After 1 second, the resolve function is called, changing the state of the Promise to Fulfilled and passing success as the result. Then, the first callback function of the then method is called and outputs success.

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("error");
  }, 1000);
});

promise.then(
  (result) => {
    console.log(result);
  },
  (error) => {
    console.log(error); // 'error'
  },
);

In this example, the initial state of the Promise is Pending. After 1 second, the reject function is called, changing the state of the Promise to Rejected, and passing error as the reason. Then, the second callback function of the then method is called, and error is output.

Promise Scenarios

  • AJAX request
  • setTimeout
  • setInterval
  • Web API

Promise Features

  • Immutability: Once the state changes to Fulfilled or Rejected, it will no longer change.
  • Chaining: You can chain calls using the then() method to handle the success or failure of asynchronous operations in order.
  • Error Handling: You can catch errors in asynchronous operations using the catch() method.

Basic Usage of Promise

Creating a Promise

const promise = new Promise((resolve, reject) => {
  // 异步操作
});

The new Promise statement accepts a function as a parameter, which has two parameters:

  • resolve: a function used to change the state of the Promise to Fulfilled.
  • reject: a function used to change the state of the Promise to Rejected.
let promise = new Promise((resolve, reject) => {
    // 异步操作
    if (/* 异步操作成功 */) {
        resolve("操作成功"); // 将 Promise 状态从 Pending 变为 Fulfilled
    } else {
        reject("操作失败"); // 将 Promise 状态从 Pending 变为 Rejected
    }
});

// 第一种写法(个人喜欢这种写法,使用命名函数来处理成功和失败,可读性高,方便代码重用)
promise.then((result) => {
    console.log("成功:" + result);
}).catch((error) => {
    console.error("失败:" + error);
});

// 第二种写法(使用匿名函数处理成功和失败)
promise.then(
 (result) => {
    // 处理成功结果
  },
  (error) => {
    // 处理失败结果
  }
);

// 第三种写法(使用命名函数处理结果)
function handleSuccess(result) {}
function handleError(error) {}
promise.then(handleSuccess, handleError);

Common Uses of Promise

Chained Execution

You can use the then method to chain multiple asynchronous operations together.

const promise1 = new Promise((resolve, reject) => {
  // 异步操作 1
});

const promise2 = new Promise((resolve, reject) => {
  // 异步操作 2
});

promise1
  .then(() => {
    return promise2;
  })
  .then((result) => {
    // 处理最终结果
  });

It can also be understood as nested execution.

Promise nesting refers to returning a new Promise instance within the then method of a Promise instance. This kind of nesting can be used to handle dependencies between multiple asynchronous operations.

Below is a simple example of Promise nesting:

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("success1");
  }, 1000);
});

promise1
  .then((result) => {
    console.log("promise1 成功fulfilled:", result);
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("success2");
      }, 2000);
    });
  })
  .then((result) => {
    console.log("promise2 成功fulfilled:", result);
  });

Precautions for Sequential Execution:

  • Nesting Promises can make the code structure complex, so it should be used with caution.
  • When using nested Promises, error handling should be considered.
  • If the nesting level is too deep, it may cause performance issues.

Alternatives to Promise Nesting:

  • Use async/await syntax
  • Use the Promise.all method
  • Use Promise's static methods Promise.resolve and Promise.reject

Parallel Execution

You can use the Promise.all method to execute multiple asynchronous operations in parallel.

const promise1 = new Promise((resolve, reject) => {
  // 异步操作 1
});

const promise2 = new Promise((resolve, reject) => {
  // 异步操作 2
});

Promise.all([promise1, promise2]).then((results) => {
  // 处理所有结果
});

Promise.all is a static method of Promise in JavaScript, used to wrap multiple Promise instances into a new Promise instance. This method will return a new Promise instance only when all the passed Promise instances are successfully fulfilled or when one of the Promise instances is rejected.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("success1");
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("success2");
  }, 2000);
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("error");
  }, 3000);
});

const allPromise = Promise.all([promise1, promise2, promise3]);

allPromise.then(
  (results) => {
    console.log("所有 Promise 实例都成功fulfilled:", results);
  },
  (error) => {
    console.error("其中一个 Promise 实例被 rejected:", error);
  },
);

The Return Value of Promise.all

The return value of the new Promise instance returned by the method depends on the state of the passed-in Promise instances:

  • If all passed-in Promise instances are successfully fulfilled, the new Promise instance will be successfully fulfilled and return an array containing the successful results of all Promise instances.
  • If any one of the Promise instances is rejected, the new Promise instance will be immediately rejected and will return the error reason of the first rejected Promise instance.

Notes on Promise.all

  • The method only waits for all passed-in Promise instances to complete, it does not execute them in the order they were passed.
  • The method does not change the state of the passed-in Promise instances.
  • If the passed-in Promise instance is not an iterable object, the method will throw a TypeError.

Regarding Whether the Return Results Have a Sequence

The return value of the new Promise instance returned by the method is an array, and the order of this array is consistent with the order of the passed-in Promise instances.

However, please note that the method does not execute the Promise instances in the order they were passed. They are executed in parallel, so their completion order may differ from the order in which they were passed.

Race Execution

This is a static method provided by Promise, used in multiple Promise instances. As long as one instance changes state first (whether Fulfilled or Rejected), it returns the return value of that first state-changed Promise instance. In other words, it is used for racing, returning the result or error of the Promise that completes the fastest.

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("promise1 resolved");
  }, 1000);
});

let promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("promise2 resolved");
  }, 500);
});

Promise.race([promise1, promise2]).then((result) => {
  console.log(result); // 输出 "promise2 resolved"
});

Error Handling

You can use the catch method to handle errors in a Promise.

promise
  .then((result) => {
    // 处理成功结果
  })
  .catch((error) => {
    // 处理失败结果
  });

Final Processing

finally method: The finally method will be called whether the Promise succeeds or fails.

promise
  .then(
    (result) => {
      // 处理成功结果
    },
    (error) => {
      // 处理失败结果
    },
  )
  .finally(() => {
    // 无论成功或失败都会执行的代码
  });

Promise Extension

Promise, Fetch, and Ajax are all technologies in JavaScript used for handling asynchronous operations. There are some key differences among them:

Promise

Promise is an object in JavaScript used to handle asynchronous operations. It makes asynchronous code easier to read and write, and helps you avoid callback hell.

The main features of Promise:

  • Can encapsulate the result of an asynchronous operation into an object
  • Can use the then method to handle the result of the asynchronous operation
  • Can use the catch method to handle errors from the asynchronous operation
  • Can use the finally method to execute code regardless of success or failure

Fetch

Fetch is an API in JavaScript used to send HTTP requests. It is easier to use than the traditional XMLHttpRequest API and provides more functionality.

The main features of Fetch:

  • Uses Promises to handle the results of a request
  • Supports multiple HTTP methods
  • Supports request headers and response headers
  • Supports streaming data transfer

Ajax

Ajax stands for Asynchronous JavaScript and XML, and it is a technology that uses JavaScript to communicate with the server without refreshing the page.

The main features of Ajax:

  • Uses the XMLHttpRequest object to send HTTP requests
  • Uses callback functions to handle the result of the request
  • Can be used to send GET, POST, PUT, DELETE, and other HTTP methods
  • Can be used to load data, update page content, etc.

Comparison

FeaturePromiseFetchAjax
PurposeHandle asynchronous operationsSend HTTP requestsCommunicate with the server
ReturnPromise objectPromise objectXMLHttpRequest object
Handlingthen methodthen methodCallback function
Errorcatch methodcatch methodError callback function
AdvantagesReadable and easy to write, avoids callback hellSimple and easy to use, powerfulGood compatibility, supports multiple browsers
DisadvantagesDeep nesting can lead to performance issuesNot supported in IE 9 or earlier versionsMessy code structure, hard to maintain

Summary

Promise, Fetch, and Ajax are all technologies used to handle asynchronous operations. Each has its advantages and is suitable for different scenarios.

  • If you need to handle general asynchronous operations, you can use Promise.
  • If you need to send HTTP requests, you can use Fetch.
  • If you need to support older browsers, you can use Ajax.

It is recommended to choose the appropriate technology based on actual needs.

Understanding the Diff Algorithm in Vue3

Detailed Introduction to the Vue3 Diff Algorithm

The Diff algorithm in Vue3 is an algorithm used to calculate the differences in the virtual DOM tree. It is used to update the real DOM as efficiently as possible when data changes.

The core idea of the DIFF algorithm is minimum path updates, which means only updating the smallest part of the virtual DOM affected by data. Implementation steps:

  1. Depth-First Traversal of the Virtual DOM Tree: Start from the root node and perform a depth-first traversal of the virtual DOM tree, generating a unique key for each node.
  2. Compare the New and Old Virtual DOM Trees: Use the key to match nodes in the new and old virtual DOM trees. If the node keys are the same, compare their attributes and child nodes. If the node keys are different, the node is considered deleted or newly added.
  3. Generate a List of Update Operations: Based on the differences between the new and old virtual DOM trees, generate a list of update operations. Update operations include:
    • Inserting nodes
    • Deleting nodes
    • Updating node attributes
    • Moving nodes
  4. Apply Update Operations: Update the real DOM according to the list of update operations.

Compared with the Diff algorithm in Vue2, the Vue3 Diff algorithm has the following improvements:

  • Faster: By adopting the concept of "minimum path update," the Vue3 Diff algorithm can update only the smallest part of the virtual DOM tree affected by data changes, making it faster.
  • Less Memory Usage: The Vue3 Diff algorithm no longer uses the "longest common subsequence" algorithm to compare two virtual DOM trees, so it uses less memory.
  • Easier to Understand: The implementation of the Vue3 Diff algorithm is simpler and easier to understand.

Vue3 Diff Algorithm Example

The following example demonstrates how the Vue3 Diff algorithm works:

<div id="app">
  <p>{{ count }}</p>
  <button @click="increment">+</button>
</div>
const app = Vue.createApp({
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    increment() {
      this.count++;
    },
  },
});

app.mount("#app");

In the initial state, the virtual DOM tree is as follows:

<div id="app">
  <p>0</p>
  <button>+</button>
</div>

When the user clicks the button, the value of count increases by 1, and the virtual DOM tree becomes:

<div id="app">
  <p>1</p>
  <button>+</button>
</div>

The Vue3 diff algorithm calculates the differences between two virtual DOM trees and generates a list of update operations. The list of update operations is as follows:

[
  {
    "type": "update",
    "node": {
      "id": "app"
    },
    "attr": {
      "textContent": "1"
    }
  }
]

According to the update operation list, Vue3 will update the real DOM and update the text content to "1".

Summary: Vue3's Diff algorithm is an efficient virtual DOM tree difference calculation algorithm, which allows Vue3 to be more efficient when updating data.

Detailed explanation of localStorage, sessionStorage, and Cookie

Common points of localStorage, sessionStorage, and Cookie:

All are stored on the browser side and are of the same origin (by the way, to explain same origin: the domain name, protocol, and port number are the same).

Differences between localStorage, sessionStorage, and Cookie:

  • Different storage sizes:
  1. The size of localStorage is generally 5M
  2. The size of sessionStorage is generally 5M
  3. The size of cookies is generally 4K
  • Different validity periods:
  1. localStorage is permanently valid unless manually deleted.
  2. sessionStorage is valid for the current session and is cleared when the page or browser is closed.
  3. cookies are valid until the set expiration date, after which they become invalid.
  • Communication with the server:
  1. localStorage does not participate in server-side communication.
  2. sessionStorage does not participate in server-side communication.
  3. cookies participate in server-side communication and are included in the HTTP headers every time (using cookies to store too much data can lead to performance issues).
  • Detailed differences in scope between localStorage and sessionStorage:
  1. Different browsers cannot share information in localStorage or sessionStorage.
  2. In the same browser, different pages can share the same localStorage (pages belonging to the same domain and port), but information in sessionStorage cannot be shared between different pages or tabs.

Discussion

Support the author
Previous post

Interviewer: Explain Set and Map

Next post

WebSocket Tutorial

LMX BlogWeb · TypeScript · Vue · Node.js
Crafted by
@LMXZQQ
Build
unavailable
Date
2026-10-30
Articles
29
Deployed on
Nginx
Source code
GitHub
License
MIT License
Typeface
Geist
Stack
  • next@16.4.3
  • react@19.3.1
  • @base-ui/react@1.8.0
  • shadcn@4.12.0
  • tailwindcss@4.3.3
Analytics
  • OpenPanel
  • Google Analytics
For agents
  • llms.txt
  • index.md
Inspired by
  1. Tailwind CSS
  2. shadcn/ui
  3. Vercel
  4. Apple
  5. Evil Charts
  6. Devouring Details
  7. Skiper UI
  8. Making Software
  9. shadcncraft
Approved by
静水流深 / LMX
1602
Command Palette

Search for a command to run...