JavaScript: Advanced Interview Tips

Front-end interview question bank (necessary for interview) recommendation: ★★★★★            

Address: front-end interview question bank

1. Closure

A closure is a function defined within a function that has access to variables of the outer function. Closures can be used to create private variables and methods, thereby protecting code from outside interference.

// 例1
function outerFunction() {
  const privateVariable = "私有变量";
  function innerFunction() {
    console.log(privateVariable); // 内部引用外部变量
  }
  return innerFunction;
}
const myFunction = outerFunction();
myFunction(); // 输出 "私有变量"

// 例2
function makeAdder(x) {  
  return function(y) {
    return x + y;
  }
}
const add5 = makeAdder(5);
add5(2); // 7

innerFunctionouterFunction Variables defined in   can be accessed  privateVariable , but outside code cannot directly access them  privateVariable.

2. Higher-order functions

A higher-order function is a function that takes one or more functions as arguments and returns a function. By using higher-order functions, you can maximize code reuse and improve code readability and maintainability. For example:

function double(num) {
  return num * 2;
}

function triple(num) {
  return num * 3;
}

function apply(fn, num) {
  return fn(num);
}

console.log(apply(double, 5)); // 输出 10
console.log(apply(triple, 5)); // 输出 15

apply is a higher-order function that takes a function and a number as arguments, calls the function, and returns the result. By using  apply functions, we avoid duplication of code.

3. Prototype chain

The prototype chain is one of the foundations of JavaScript object-oriented programming. Each JavaScript object has a prototype object, and through the prototype chain, we can realize the inheritance relationship between objects. For example:

function Animal(name, sound) {
  this.name = name;
  this.sound = sound;
}

Animal.prototype.makeSound = function() {
  console.log(this.sound);
};

function Dog(name, sound) {
  Animal.call(this, name, sound);
}

Dog.prototype = Object.create(Animal.prototype);

Dog.prototype.bark = function() {
  console.log("Woof!");
};

const myDog = new Dog("Buddy", "Bark");
myDog.makeSound(); // 输出 "Bark"
myDog.bark(); // 输出 "Woof!"

Animal is a constructor, it has a  makeSound method, Dog constructors inherit from  Animal constructors, and add a  bark method. By using the prototype chain, we realize that  Dog the object inherits  Animal the properties and methods of the object.

4. Function currying

Function currying refers to converting a function that takes multiple arguments into a series of functions that take only one argument. By using function currying, you can simplify how functions are called and improve the readability and maintainability of your code.

function multiply(a, b) {
  return a * b;
}

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return function(...moreArgs) {
        return curried.apply(this, args.concat(moreArgs));
      };
    }
  };
}

const curriedMultiply = curry(multiply);
console.log(curriedMultiply(2)(3)); // 输出 6

curry is a function that takes a function as an argument and returns a new function. By using  curry a function, we  multiply convert the function into a function that only accepts one parameter, which can be more convenient and flexible when calling.

5. Function throttling and function anti-shake

Function throttling and function debounce are two commonly used performance optimization techniques.

Function throttling refers to executing a function only once within a certain period of time.

Function anti-shake means that only the last function is executed within a certain period of time.

Both can help us avoid frequently triggering functions, thereby improving the performance of the code and the user experience.

// 节流
function throttle(fn,waitTime) { 
    let timer;
    return function(...args) { 
        if (!timer) { 
            timer = setTimeout(() => { 
                fn.apply(this, args); 
                timer = null; 
            }, waitTime); 
        } 
    }; 
}
// 防抖
function debounce(fn, waitTime) { 
    let timer;
    return function(...args) { 
        clearTimeout(timer);
        timer = setTimeout(() => {
          fn.apply(this, args);
        }, waitTime);
    }; 
}

const throttledFunction = throttle(() => console.log("Throttled function"), 1000);
const debouncedFunction = debounce(() => console.log("Debounced function"), 1000);// 在短时间内多次调用函数
for (let i = 0; i < 10; i++) {
    throttledFunction();
    debouncedFunction();
}
// 输出 
// Throttled function
// Debounced function

The throttle and debounce functions both take a function and a wait time as arguments and return a new function. By using these two techniques, we can avoid triggering functions multiple times in a short period of time, thereby improving code performance and user experience.

6. Promises

Promise is a solution for asynchronous programming, it is used to handle asynchronous operations and return results. Promise has three states: pending, resolved, and rejected, which respectively indicate that the asynchronous operation is in progress, the operation has been successfully completed, and the operation has not been successfully completed.

function fetchData() {
    return new Promise((resolve, reject) => {
        // 异步操作
        setTimeout(() => {
            const data = { name: "John", age: 30 };
            if (data) {
                resolve(data);
            } else {
                reject(new Error("Failed to fetch data"));
            }
        }, 1000);
    });
}

fetchData().then(data => console.log(data)).catch(error => console.error(error));

The fetchData function returns a Promise object, and returns the result or error message through the `resolve` or `reject` method after the asynchronous operation is completed. By using then and catch` methods, we can get the result of an asynchronous operation and process it.

7. async/await

async/await is a Promise-based asynchronous programming solution that provides a more concise and intuitive way to handle asynchronous operations. async function is used to declare an asynchronous function, and await is used to wait for the result of an asynchronous operation.

function fetchData( {
    return new Promise((resolve, reject) => {
      // 异步操作
      setTimeout(() => {
        const data = { name: "John", age: 30 };
        if (data) {
           resolve(data);
        } else {
           reject(new Error("Failed to fetch data"));
        }
      }, 1000);
    });
  }

 async function getData() {
    try {
      const data = await fetchData();
      console.log(data);
    } catch (error) {
      console.error(error);
    }
  }

getData();

The getData function declares an asynchronous function using the async keyword, and internally waits for the result of the asynchronous operation through the await keyword. By using try/catch statement, we can catch possible errors of asynchronous operation.

8. ES6 Modularization

ES6 modularity is a new modular syntax introduced by ECMAScript 6, which provides a simple and reliable way to organize JavaScript code and make the code easier to reuse and maintain. ES6 modularity uses `import` and `export` keywords to import and export modules.

// math.js
export function add(a, b) {
    return a + b;
}
export function subtract(a, b) {
    return a - b;
}

// main.js
import { add, subtract } from "./math.js";
console.log(add(2, 3));      // 输出 5
console.log(subtract(3, 2)); // 输出 1

The math.js module exports two functions add and subtract. In main.js, these two functions are imported via the import keyword and used internally to perform various operations.

Nine, Map and Set data structure

Map and Set are two new data structures introduced by ES6, both of which provide a more efficient and flexible way to store and process data. Map is a collection of key-value pairs, where each key corresponds to a unique value; while Set is an unordered, non-repeating collection of elements.

const myMap = new Map();

myMap.set("key1", "value1");
myMap.set("key2", "value2");

console.log(myMap.get("key1")); // 输出 "value1"

const mySet = new Set([1, 2, 3, 3, 4]);

console.log(mySet.size); // 输出 4
console.log(mySet.has(3)); // 输出 true

10. Classes and Objects

Classes and objects are one of the foundations of JavaScript object-oriented programming, and they provide an abstract and encapsulated way to organize and manage code. A class is an abstract type used to describe objects with similar properties and methods, and an object is an instantiation of a class.

class Animal {
  constructor(name, sound) {
    this.name = name;
    this.sound = sound;
  }
  
  makeSound() {
    console.log(this.sound);
  }
}

class Dog extends Animal {
  constructor(name, sound) {
    super(name, sound);
  }
  
  bark() {
    console.log("Woof!");
  }
}

const myDog = new Dog("Buddy", "Bark");
myDog.makeSound(); // 输出 "Bark"
myDog.bark(); // 输出 "Woof!"

// 原型继承
const animal = {
  walk() {
    console.log('Walking...');
  }
};

const dog = Object.create(animal);
dog.bark = function() {
  console.log('Barking...');
}

dog.walk(); // Walking...
dog.bark(); // Barking...

First define a  Animal class named , and add a  makeSound method named to it. Also defined a  Dog subclass named and added a  bark method named to it. By using  extends keywords,  Dog the class can inherit  Animal the properties and methods of the class. Finally, an object named is created  myDog which is  Dog an instantiation of the class.

Of course, there are many other techniques, such as lazy evaluation, recursion and so on. Mastering these techniques will allow you to better understand JavaScript and write more efficient and elegant code.

Front-end interview question bank (necessary for interview) recommendation: ★★★★★            

Address: front-end interview question bank

Guess you like

Origin blog.csdn.net/weixin_42981560/article/details/131822272