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
innerFunction
outerFunction
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