地址:web前端面试题库
不管你是一年经验还是两年经验,在面试的时候问到js相关的一些高阶知识总是会模棱两可,谈吐不清? 本篇文章将通过代码的示例阐述十个高阶js的知识~
闭包是指函数中定义的函数,它可以访问外部函数的变量。闭包可以用来创建私有变量和方法,从而保护代码不受外界干扰。
- // 例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
中定义的 privateVariable
变量,但外部的代码无法直接访问 privateVariable
。
高阶函数是指接受一个或多个函数作为参数,并返回一个函数的函数。通过使用高阶函数,你可以将代码复用最大化,并提高代码的可读性和可维护性。例如:
- 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
是一个高阶函数,它接受一个函数和一个数字作为参数,并调用该函数并返回结果。通过使用 apply
函数,我们避免了重复书写代码。
原型链是JavaScript面向对象编程的基础之一。每个JavaScript对象都有一个原型对象,通过原型链,我们可以实现对象之间的继承关系。例如:
- 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
是一个构造函数,它有一个 makeSound
方法,Dog
构造函数继承自 Animal
构造函数,并添加了一个 bark
方法。通过使用原型链,我们实现了 Dog
对象继承了 Animal
对象的属性和方法。
函数柯里化是指将一个接收多个参数的函数转换成一系列只接收一个参数的函数。通过使用函数柯里化,你可以简化函数的调用方式,并提高代码的可读性和可维护性。
- 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
是一个函数,它接受一个函数作为参数,并返回一个新的函数。通过使用 curry
函数,我们将 multiply
函数转换成了一个只接收一个参数的函数,在调用时可以更加方便和灵活。
函数节流和函数防抖是两种常用的性能优化技巧。
函数节流指在一定时间内只执行一次函数,
函数防抖指在一定时间内只执行最后一次函数。
两种都可以帮助我们避免频繁触发函数,从而提高代码的性能和用户体验。
- // 节流
- 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
throttle 和 debounce 函数都接受一个函数和一个等待时间作为参数,并返回一个新的函数。通过使用这两种技巧,我们可以避免在短时间内多次触发函数,从而提高代码性能和用户体验。
Promise是一种用于异步编程的解决方案,它用于处理异步操作并返回结果。Promise有三种状态:pending、resolved和rejected,分别表示异步操作正在进行、操作已成功完成和操作未成功完成。
- 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));
fetchData 函数返回一个Promise对象,并在异步操作完成后通过 resolve
或 reject
方法来返回结果或错误信息。通过使用then
和 catch
方法,我们可以获取异步操作的结果并进行处理。
async/await是一种基于Promise的异步编程解决方案,它提供了更加简洁和直观的方式来处理异步操作。async函数用于声明一个异步函数,而await用于等待一个异步操作的结果。
- 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();
getData 函数使用async关键字声明一个异步函数,并在内部通过await关键字等待异步操作的结果。通过使用try/catch语句,我们可以捕获异步操作可能出现的错误。
ES6模块化是ECMAScript 6引入的一种新的模块化语法,它提供了一种简单且可靠的方式来组织JavaScript代码,并使得代码更加易于重用和维护。ES6模块化使用import
和export
关键字来导入和导出模块。
- // 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
math.js 的模块导出了两个函数 add 和 subtract。在 main.js 中,通过 import 关键字将这两个函数导入,并在内部使用它们来执行各种操作。
Map和Set是ES6引入的两个新的数据结构,它们都提供了一种更加高效和灵活的方式来存储和处理数据。Map是一种键值对集合,其中每个键唯一对应一个值;而Set是一种无序的、不重复的元素集合。
- 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
类和对象是JavaScript面向对象编程的基础之一,它们提供了一种抽象化和封装化的方式来组织和管理代码。类是一种抽象类型,用于描述具有相似属性和方法的对象,而对象则是类的实例化。
- 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...
先定义了一个名为 Animal 的类,并在其中添加了一个名为 makeSound 的方法。还定义了一个名为 Dog 的子类,并在其中添加了一个名为 bark 的方法。通过使用 extends 关键字,使得 Dog 类可以继承 Animal 类的属性和方法。最后,创建了一个名为 myDog 的对象,该对象是 Dog 类的实例化。
当然还有很多其他的技巧,比如惰性求值、递归等等。掌握这些技巧可以让你更好地理解JavaScript,并写出更加高效、优雅的代码。欢迎大家评论补充~
地址:web前端面试题库