当前位置: 首页 > news >正文

Javascript面试题及详细答案150道之(106-120)

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。

前后端面试题-专栏总目录

在这里插入图片描述

文章目录

  • 一、本文面试题目录
      • 106. 如何在JavaScript中实现一个简单的哈希表(Hash Table)?
      • 107. JavaScript中`String.prototype.codePointAt()`和`charCodeAt()`的区别是什么?
      • 108. 如何在JavaScript中实现一个简单的图(Graph)数据结构?
      • 109. JavaScript中`Array.prototype.some()`和`Array.prototype.every()`的区别是什么?
      • 110. 如何在JavaScript中实现一个简单的状态机(State Machine)?
      • 111. JavaScript中`Intl`对象的作用是什么?
      • 112. 如何在JavaScript中实现一个简单的LRU缓存(Least Recently Used Cache)?
      • 113. JavaScript中`String.prototype.replaceAll()`和`replace()`的区别是什么?
      • 114. 如何在JavaScript中实现一个简单的WebSocket客户端?
      • 115. JavaScript中`Array.prototype.reduceRight()`的作用是什么?
      • 116. 如何在JavaScript中实现一个简单的发布-订阅模式?
      • 117. JavaScript中`Object.is()`和`===`的区别是什么?
      • 118. 如何在JavaScript中实现一个简单的防抖函数(Debounce)?
      • 119. JavaScript中`async`函数和普通函数的区别是什么?
      • 120. 如何在JavaScript中实现一个简单的节流函数(Throttle)?
  • 二、150道面试题目录列表

一、本文面试题目录

106. 如何在JavaScript中实现一个简单的哈希表(Hash Table)?

哈希表实现
使用数组和哈希函数,处理冲突采用链地址法(每个槽位存储链表)。

代码示例

class HashTable {constructor(size = 53) {this.keyMap = new Array(size);}// 哈希函数(将键转换为数组索引)_hash(key) {let total = 0;const WEIRD_PRIME = 31;for (let i = 0; i < Math.min(key.length, 100); i++) {const char = key[i];const value = char.charCodeAt(0) - 96;total = (total * WEIRD_PRIME + value) % this.keyMap.length;}return total;}// 设置键值对set(key, value) {const index = this._hash(key);if (!this.keyMap[index]) {this.keyMap[index] = [];}// 处理键已存在的情况(更新值)for (let i = 0; i < this.keyMap[index].length; i++) {if (this.keyMap[index][i][0] === key) {this.keyMap[index][i][1] = value;return;}}this.keyMap[index].push([key, value]);}// 获取键对应的值get(key) {const index = this._hash(key);if (this.keyMap[index]) {for (let i = 0; i < this.keyMap[index].length; i++) {if (this.keyMap[index][i][0] === key) {return this.keyMap[index][i][1];}}}return undefined;}// 获取所有键keys() {const keysArr = [];for (let i = 0; i < this.keyMap.length; i++) {if (this.keyMap[i]) {for (let j = 0; j < this.keyMap[i].length; j++) {if (!keysArr.includes(this.keyMap[i][j][0])) {keysArr.push(this.keyMap[i][j][0]);}}}}return keysArr;}
}// 使用示例
const ht = new HashTable(3);
ht.set('apple', 10);
ht.set('banana', 20);
ht.set('cherry', 30);
console.log(ht.get('banana')); // 20
console.log(ht.keys()); // ["apple", "banana", "cherry"]

107. JavaScript中String.prototype.codePointAt()charCodeAt()的区别是什么?

核心区别

方法返回值范围处理Unicode补充字符示例("😀".codePointAt(0) vs "😀".charCodeAt(0)
codePointAt(index)完整码点值(0~0x10FFFF)128512(对应U+1F600
charCodeAt(index)UTF-16编码单元值(0~65535)❌(需两个代码单元表示补充字符)55357(高代理部分,需结合charCodeAt(1)获取完整值)

代码示例

const str = "😀"; // Unicode补充字符(U+1F600)// codePointAt()
console.log(str.codePointAt(0)); // 128512(完整码点值)
console.log(str.codePointAt(1)); // 56832(低代理部分的值)// charCodeAt()
console.log(str.charCodeAt(0)); // 55357(高代理部分)
console.log(str.charCodeAt(1)); // 56832(低代理部分)// 判断是否为高代理部分
function isHighSurrogate(charCode) {return charCode >= 0xD800 && charCode <= 0xDBFF;
}// 判断是否为补充字符
function isSupplementaryCodePoint(codePoint) {return codePoint > 0xFFFF;
}

应用场景
处理包含表情符号、罕见字符等补充字符的字符串时,需使用codePointAt()确保获取完整码点值。

108. 如何在JavaScript中实现一个简单的图(Graph)数据结构?

图的实现
使用邻接表表示,支持添加顶点、添加边、遍历等操作。

代码示例

class Graph {constructor() {this.adjacencyList = {};}// 添加顶点addVertex(vertex) {if (!this.adjacencyList[vertex]) {this.adjacencyList[vertex] = [];}}// 添加边(无向图)addEdge(vertex1, vertex2) {this.adjacencyList[vertex1].push(vertex2);this.adjacencyList[vertex2].push(vertex1);}// 移除边removeEdge(vertex1, vertex2) {this.adjacencyList[vertex1] = this.adjacencyList[vertex1].filter(v => v!== vertex2);this.adjacencyList[vertex2] = this.adjacencyList[vertex2].filter(v => v!== vertex1);}// 移除顶点removeVertex(vertex) {while (this.adjacencyList[vertex].length) {const adjacentVertex = this.adjacencyList[vertex].pop();this.removeEdge(vertex, adjacentVertex);}delete this.adjacencyList[vertex];}// 深度优先遍历(递归)depthFirstRecursive(start) {const result = [];const visited = {};const adjacencyList = this.adjacencyList;(function dfs(vertex) {if (!vertex) return null;visited[vertex] = true;result.push(vertex);adjacencyList[vertex].forEach(neighbor => {if (!visited[neighbor]) {return dfs(neighbor);}});})(start);return result;}
}// 使用示例
const graph = new Graph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addEdge('A', 'B');
graph.addEdge('A', 'C');
console.log(graph.depthFirstRecursive('A')); // ["A", "B", "C"]

109. JavaScript中Array.prototype.some()Array.prototype.every()的区别是什么?

核心区别

方法判断逻辑返回值终止条件
some(callback)至少有一个元素满足条件truefalse找到第一个满足条件的元素
every(callback)所有元素都满足条件truefalse找到第一个不满足条件的元素

代码示例

const numbers = [1, 3, 5, 7, 8];// some()
console.log(numbers.some(num => num % 2 === 0)); // true(存在偶数8)// every()
console.log(numbers.every(num => num % 2 === 0)); // false(并非所有都是偶数)
console.log(numbers.every(num => num < 10)); // true(所有元素都小于10)// 终止条件演示
const arr = [2, 4, 5, 6];
arr.some(num => {console.log(num); // 输出2后终止(找到偶数)return num % 2 === 0;
});arr.every(num => {console.log(num); // 输出2、4、5后终止(找到奇数)return num % 2 === 0;
});

110. 如何在JavaScript中实现一个简单的状态机(State Machine)?

状态机实现
定义状态、转换规则和动作,支持状态转移和事件处理。

代码示例

class StateMachine {constructor(initialState, states) {this.currentState = initialState;this.states = states;}// 触发事件,转移到下一个状态transition(event) {const currentStateConfig = this.states[this.currentState];const nextState = currentStateConfig.transitions[event];if (!nextState) {console.error(`Invalid event "${event}" for state "${this.currentState}"`);return;}// 执行退出动作if (currentStateConfig.onExit) {currentStateConfig.onExit(event);}// 转移到新状态this.currentState = nextState;// 执行进入动作const newStateConfig = this.states[this.currentState];if (newStateConfig.onEnter) {newStateConfig.onEnter(event);}return this.currentState;}// 获取当前状态getState() {return this.currentState;}
}// 使用示例
const trafficLightStates = {green: {transitions: {timer: 'yellow'},onEnter: () => console.log('绿灯亮起'),onExit: () => console.log('绿灯熄灭')},yellow: {transitions: {timer: 'red'},onEnter: () => console.log('黄灯亮起'),onExit: () => console.log('黄灯熄灭')},red: {transitions: {timer: 'green'},onEnter: () => console.log('红灯亮起'),onExit: () => console.log('红灯熄灭')}
};const trafficLight = new StateMachine('green', trafficLightStates);
trafficLight.transition('timer'); // 绿灯 → 黄灯
trafficLight.transition('timer'); // 黄灯 → 红灯

111. JavaScript中Intl对象的作用是什么?

Intl对象
ES6引入的国际化API,提供语言敏感的字符串比较、数字格式化和日期时间格式化。

核心功能

  1. 字符串比较

    const str1 = 'ä';
    const str2 = 'z';// 按英语排序(ä在z后)
    const enCollator = new Intl.Collator('en');
    console.log(enCollator.compare(str1, str2)); // 1(大于)// 按德语排序(ä在a后,z前)
    const deCollator = new Intl.Collator('de');
    console.log(deCollator.compare(str1, str2)); // -1(小于)
    
  2. 数字格式化

    const num = 1234567.89;// 美国格式
    const usFormatter = new Intl.NumberFormat('en-US');
    console.log(usFormatter.format(num)); // "1,234,567.89"// 德国格式
    const deFormatter = new Intl.NumberFormat('de-DE');
    console.log(deFormatter.format(num)); // "1.234.567,89"// 货币格式化
    const currencyFormatter = new Intl.NumberFormat('zh-CN', {style: 'currency',currency: 'CNY'
    });
    console.log(currencyFormatter.format(1000)); // "¥1,000.00"
    
  3. 日期时间格式化

    const date = new Date();// 美国格式
    const usDateFormatter = new Intl.DateTimeFormat('en-US');
    console.log(usDateFormatter.format(date)); // "7/21/2025"// 日本格式
    const jpDateFormatter = new Intl.DateTimeFormat('ja-JP');
    console.log(jpDateFormatter.format(date)); // "2025/7/21"// 自定义格式
    const customFormatter = new Intl.DateTimeFormat('zh-CN', {year: 'numeric',month: 'long',day: 'numeric',hour: '2-digit',minute: '2-digit'
    });
    console.log(customFormatter.format(date)); // "2025年7月21日 14:30"
    

112. 如何在JavaScript中实现一个简单的LRU缓存(Least Recently Used Cache)?

LRU缓存实现
使用Map(保持插入顺序)实现,最近访问的元素移到末尾,容量满时删除头部元素。

代码示例

class LRUCache {constructor(capacity) {this.capacity = capacity;this.cache = new Map();}// 获取缓存项get(key) {if (!this.cache.has(key)) return -1;// 将访问的元素移到Map末尾(表示最近使用)const value = this.cache.get(key);this.cache.delete(key);this.cache.set(key, value);return value;}// 添加缓存项put(key, value) {// 如果键已存在,先删除if (this.cache.has(key)) {this.cache.delete(key);} // 添加新项到Map末尾this.cache.set(key, value);// 如果超过容量,删除最久未使用的项(Map头部)if (this.cache.size > this.capacity) {this.cache.delete(this.cache.keys().next().value);}}
}// 使用示例
const cache = new LRUCache(2);
cache.put(1, 'one');
cache.put(2, 'two');
console.log(cache.get(1)); // "one"
cache.put(3, 'three'); // 容量满,删除最久未使用的2
console.log(cache.get(2)); // -1(未找到)

原理
Map的迭代顺序与插入顺序一致,通过删除并重新插入元素,将其移到末尾,头部元素即为最久未使用的项。

113. JavaScript中String.prototype.replaceAll()replace()的区别是什么?

核心区别

方法匹配方式正则表达式标志替换全部匹配兼容性
replace(pattern, replacement)单个匹配或正则匹配支持g标志需手动加g所有浏览器
replaceAll(pattern, replacement)全部匹配不支持g标志ES2021(现代浏览器)

代码示例

const str = "Hello World, Hello JavaScript";// replace() 只替换第一个匹配(无g标志)
console.log(str.replace("Hello", "Hi")); // "Hi World, Hello JavaScript"// replace() 替换所有匹配(需g标志)
console.log(str.replace(/Hello/g, "Hi")); // "Hi World, Hi JavaScript"// replaceAll() 直接替换所有匹配
console.log(str.replaceAll("Hello", "Hi")); // "Hi World, Hi JavaScript"// replaceAll() 使用正则(但不能有g标志)
console.log(str.replaceAll(/Hello/, "Hi")); // "Hi World, Hi JavaScript"
console.log(str.replaceAll(/Hello/g, "Hi")); // 错误:正则不能有g标志

注意
replaceAll()在不支持的浏览器中需使用replace()g标志替代。

114. 如何在JavaScript中实现一个简单的WebSocket客户端?

WebSocket客户端实现
使用WebSocket API创建实时双向通信。

代码示例

// 创建WebSocket连接
const socket = new WebSocket('ws://echo.websocket.org');// 连接建立时触发
socket.onopen = (event) => {console.log('WebSocket连接已建立');// 发送消息到服务器socket.send('Hello, server!');
};// 接收到消息时触发
socket.onmessage = (event) => {console.log('收到服务器消息:', event.data);
};// 连接关闭时触发
socket.onclose = (event) => {console.log('WebSocket连接已关闭');if (event.wasClean) {console.log(`关闭码: ${event.code}, 原因: ${event.reason}`);} else {console.log('连接异常关闭');}
};// 发生错误时触发
socket.onerror = (error) => {console.error('WebSocket错误:', error);
};// 关闭连接
function closeConnection() {socket.close(1000, '用户主动关闭');
}

处理二进制数据

// 接收二进制数据
socket.binaryType = 'arraybuffer';
socket.onmessage = (event) => {if (event.data instanceof ArrayBuffer) {const buffer = event.data;// 处理ArrayBuffer...}
};// 发送二进制数据
const uint8Array = new Uint8Array([72, 101, 108, 108, 111]); // "Hello"
socket.send(uint8Array);

115. JavaScript中Array.prototype.reduceRight()的作用是什么?

reduceRight()
reduce()类似,但从数组的最后一个元素开始,向前遍历到第一个元素。

语法

array.reduceRight((accumulator, currentValue, index, array) => {// 返回累加值
}, initialValue);

代码示例

// 数组扁平化(从右到左)
const nested = [[1, 2], [3, 4], [5, 6]];
const flattened = nested.reduceRight((acc, arr) => acc.concat(arr), []);
console.log(flattened); // [5, 6, 3, 4, 1, 2]// 与reduce()对比
const result1 = [1, 2, 3].reduce((acc, num) => acc - num, 0); // (0-1)-2-3 = -6
const result2 = [1, 2, 3].reduceRight((acc, num) => acc - num, 0); // (0-3)-2-1 = -6// 字符串连接顺序
const words = ['Hello', ' ', 'World', '!'];
const str1 = words.reduce((acc, word) => acc + word); // "Hello World!"
const str2 = words.reduceRight((acc, word) => acc + word); // "!World Hello"

应用场景

  • 需要从右到左处理数组时(如解析嵌套结构)。
  • 操作顺序敏感的累加器(如字符串连接)。

116. 如何在JavaScript中实现一个简单的发布-订阅模式?

发布-订阅模式实现
通过事件中心解耦发布者和订阅者,支持事件注册、发布和取消。

代码示例

class EventEmitter {constructor() {this.events = {};}// 订阅事件on(eventName, callback) {if (!this.events[eventName]) {this.events[eventName] = [];}this.events[eventName].push(callback);return this;}// 发布事件emit(eventName, ...args) {if (this.events[eventName]) {this.events[eventName].forEach(callback => callback(...args));}return this;}// 取消订阅(移除特定回调)off(eventName, callback) {if (this.events[eventName]) {this.events[eventName] = this.events[eventName].filter(cb => cb!== callback);}return this;}// 只执行一次的订阅once(eventName, callback) {const wrapper = (...args) => {callback(...args);this.off(eventName, wrapper);};this.on(eventName, wrapper);return this;}
}// 使用示例
const emitter = new EventEmitter();// 订阅事件
const callback = (data) => console.log('接收到:', data);
emitter.on('message', callback);// 发布事件
emitter.emit('message', 'Hello, Subscribers!'); // 输出:接收到: Hello, Subscribers!// 取消订阅
emitter.off('message', callback);
emitter.emit('message', '再次发送'); // 无输出// 一次性订阅
emitter.once('single', () => console.log('只执行一次'));
emitter.emit('single'); // 输出:只执行一次
emitter.emit('single'); // 无输出

117. JavaScript中Object.is()===的区别是什么?

核心区别

比较操作NaNNaN+0-0普通值比较
Object.is(a, b)truefalse===
a === bfalsetrueObject.is

代码示例

// NaN比较
console.log(Object.is(NaN, NaN)); // true
console.log(NaN === NaN); // false// +0与-0比较
console.log(Object.is(+0, -0)); // false
console.log(+0 === -0); // true// 普通值比较
console.log(Object.is(5, 5)); // true
console.log(5 === 5); // trueconsole.log(Object.is('hello', 'hello')); // true
console.log('hello' === 'hello'); // trueconsole.log(Object.is(null, null)); // true
console.log(null === null); // true

实现Object.is的等效逻辑

function myObjectIs(a, b) {if (a === b) {// 处理+0和-0return a!== 0 || 1 / a === 1 / b;} else {// 处理NaNreturn a!== a && b!== b;}
}

118. 如何在JavaScript中实现一个简单的防抖函数(Debounce)?

防抖函数
延迟执行函数,若在延迟期间再次触发,则重新计时,直到最后一次触发后才执行。

代码示例

function debounce(func, delay) {let timer = null;return function(...args) {// 清除上一次的定时器if (timer) {clearTimeout(timer);}// 设置新的定时器,延迟执行函数timer = setTimeout(() => {func.apply(this, args);timer = null;}, delay);};
}// 使用示例
const searchInput = document.getElementById('search');// 防抖处理搜索输入
const debouncedSearch = debounce((event) => {console.log('搜索:', event.target.value);// 执行搜索逻辑...
}, 300);searchInput.addEventListener('input', debouncedSearch);

带立即执行选项的防抖

function debounce(func, delay, immediate = false) {let timer = null;return function(...args) {const shouldCallNow = immediate &&!timer;// 清除上一次的定时器if (timer) {clearTimeout(timer);}// 设置新的定时器timer = setTimeout(() => {timer = null;if (!immediate) {func.apply(this, args);}}, delay);// 立即执行if (shouldCallNow) {func.apply(this, args);}};
}

119. JavaScript中async函数和普通函数的区别是什么?

核心区别

特性async函数普通函数
返回值始终返回Promise返回指定值或undefined
await支持可使用await暂停执行不能使用await
错误处理可使用try...catch捕获异步错误需依赖回调或Promise的.catch()
执行方式异步执行(但代码结构像同步)同步执行(除非显式使用异步API)

代码示例

// 普通函数
function fetchData() {return fetch('https://api.example.com/data').then(response => response.json());
}// async函数
async function fetchDataAsync() {try {const response = await fetch('https://api.example.com/data');const data = await response.json();return data;} catch (error) {console.error('获取数据失败:', error);throw error;}
}// 调用对比
fetchData().then(data => console.log(data)).catch(error => console.error(error));fetchDataAsync().then(data => console.log(data)).catch(error => console.error(error));

异步执行示例

async function asyncExample() {console.log('开始');await new Promise(resolve => setTimeout(resolve, 1000));console.log('等待1秒后');return '完成';
}// 调用async函数
console.log('调用前');
asyncExample().then(result => console.log(result));
console.log('调用后');// 输出顺序:
// 调用前
// 开始
// 调用后
// 等待1秒后
// 完成

120. 如何在JavaScript中实现一个简单的节流函数(Throttle)?

节流函数
限制函数在一定时间内最多执行一次,即使触发多次也只执行一次。

代码示例

// 时间戳实现(立即执行)
function throttle(func, limit) {let lastExecTime = 0;return function(...args) {const now = Date.now();// 如果距离上次执行超过限制时间,则执行函数if (now - lastExecTime >= limit) {func.apply(this, args);lastExecTime = now;}};
}// 使用示例
window.addEventListener('scroll', throttle(() => {console.log('滚动事件被触发(节流)');
}, 500));

定时器实现(延迟执行)

function throttle(func, limit) {let timer = null;return function(...args) {// 如果定时器不存在,则设置定时器if (!timer) {timer = setTimeout(() => {func.apply(this, args);timer = null;}, limit);}};
}

结合版(立即执行+延迟执行)

function throttle(func, limit) {let lastExecTime = 0;let timer = null;return function(...args) {const now = Date.now();const remaining = limit - (now - lastExecTime);// 如果距离上次执行超过限制时间,立即执行if (remaining <= 0) {if (timer) {clearTimeout(timer);timer = null;}func.apply(this, args);lastExecTime = now;} // 否则设置定时器,在剩余时间后执行else if (!timer) {timer = setTimeout(() => {func.apply(this, args);lastExecTime = Date.now();timer = null;}, remaining);}};
}

二、150道面试题目录列表

文章序号Javascript面试题150道
1Javascript面试题及答案150道(001-015)
2Javascript面试题及答案150道(016-030)
3Javascript面试题及答案150道(031-045)
4Javascript面试题及答案150道(046-060)
5Javascript面试题及答案150道(061-075)
6Javascript面试题及答案150道(076-090)
7Javascript面试题及答案150道(091-105)
8Javascript面试题及答案150道(106-120)
9Javascript面试题及答案150道(121-135)
10Javascript面试题及答案150道(136-150)
http://www.lryc.cn/news/623698.html

相关文章:

  • Python实现区域生长和RANSAC聚类
  • 职场新人如何在快速适应工作的同时保持自我成长节奏?
  • JUC常用线程辅助类详解
  • JavaScript 性能优化实战大纲
  • [GLM-4.5] LLM推理服务器(SGLang/vLLM) | 工具与推理解析器
  • c_str()函数的详细解析
  • 【PHP】Hyperf:接入 Nacos
  • Python | 解决 matplotlib 中文乱码
  • 基于MATLAB多智能体强化学习的出租车资源配置优化系统设计与实现
  • [论文阅读] 人工智能 + 职业教育 | 从技能操作者到技术反思者:生成式AI驱动职业教育学习范式转型
  • 豆包 Java的23种设计模式
  • 微调 AnomalyCLIP——基于对象无关提示学习与全局 - 局部优化的零样本异常检测框架性能验证
  • 迅速掌握Git通用指令
  • 7 索引的监控
  • 编程算法实例-整数分解质因数
  • Mac(五)自定义鼠标滚轮方向 LinearMouse
  • 又一家茑屋书店即将歇业,精品书店的未来在哪里?
  • Bee1.17.25更新Bug,完善功能.不支持NOSQL,分库分表Sharding(2.X版有)
  • Spark03-RDD02-常用的Action算子
  • YOLO12 改进、魔改|频域自注意力求解器FSAS,通过频域高效计算自注意力,在降低时间与空间复杂度的同时保留关键特征信息,提升遮挡、小目标检测
  • PostgreSQL——用户管理
  • 【IDEA】设置Debug调试时调试器不进入特定类(Spring框架、Mybatis框架)
  • Day3--滑动窗口与双指针--2461. 长度为 K 子数组中的最大和,1423. 可获得的最大点数,1052. 爱生气的书店老板
  • 【算法】模拟专题
  • JavaScript性能优化实战(三):DOM操作性能优化
  • openEuler等Linux系统中如何复制移动硬盘的数据
  • 【Luogu】每日一题——Day20. P4366 [Code+#4] 最短路 (图论)
  • 计算机网络 Session 劫持 原理和防御措施
  • 【Luogu】每日一题——Day21. P3556 [POI 2013] MOR-Tales of seafaring (图论)
  • 裸机框架:按键模组