百度前端面试核心考点深度解析(二)
看到你整理的这些前端面试题目,确实都是非常经典和重要的考点。下面我将为你逐一进行详细解析,帮助你系统性地准备。
1. 怎么判断对象类型,typeof和instanceof用法区别
核心考察点
- 类型判断的各种方法及其适用场景
- 对JavaScript类型系统的深入理解
详细解析
typeof 运算符:
typeof 'hello' // "string"
typeof 123 // "number"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object" (历史遗留问题)
typeof {} // "object"
typeof [] // "object" (无法区分数组)
typeof function(){} // "function"
instanceof 运算符:
[] instanceof Array // true
{} instanceof Object // true
new Date() instanceof Date // truefunction Person() {}
const p = new Person()
p instanceof Person // true
其他判断方法:
// 判断数组
Array.isArray([]) // true
Object.prototype.toString.call([]) // "[object Array]"// 判断正则对象
Object.prototype.toString.call(/regex/) // "[object RegExp]"// 判断日期对象
Object.prototype.toString.call(new Date()) // "[object Date]"// 最可靠的通用方法
function getType(obj) {return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
}
2. new的原理
核心实现机制
function myNew(constructor, ...args) {// 1. 创建一个新对象,继承构造函数的prototypeconst obj = Object.create(constructor.prototype)// 2. 执行构造函数,将this绑定到新对象const ret = constructor.apply(obj, args)// 3. 如果构造函数返回对象,则返回该对象;否则返回新对象return ret instanceof Object ? ret : obj
}// 使用示例
function Person(name) {this.name = name
}
const p = myNew(Person, '张三')
3. 事件循环(浏览器与Node.js)
浏览器事件循环机制
宏任务(Macrotask): script整体代码、setTimeout、setInterval、I/O、UI渲染
微任务(Microtask): Promise.then、MutationObserver、process.nextTick(Node.js)执行顺序:同步代码 → 微任务 → 宏任务 → 微任务...
Node.js与浏览器差异
- Node.js:有6个阶段(timers、pending callbacks、idle、poll、check、close)
- 浏览器:相对简单,主要区分宏任务和微任务
4. 原型链和继承
原型链示意图
实例对象 → 构造函数.prototype → Object.prototype → null
实现继承的几种方式
// 1. 原型链继承
function Parent() { this.name = 'parent' }
function Child() {}
Child.prototype = new Parent()// 2. 构造函数继承
function Child() { Parent.call(this) }// 3. 寄生继承(最常用)
function Child() { Parent.call(this) }
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Childfunction Child(){Parent.call(this)};
Child.prototype=Object.create(Parent.prototype);
Child.prototype.constructor=Child;// 4. Class继承(ES6)
class Child extends Parent {constructor() { super() }
}
5. 大文件上传
大文件上传
核心实现方案
// 1. 文件分片
const chunkSize = 5 * 1024 * 1024 // 5MB
const chunks = []
for (let i = 0; i < file.size; i += chunkSize) {chunks.push(file.slice(i, i + chunkSize))
}// 2. 计算文件hash(用于断点续传)
async function calculateHash(chunks) {return new Promise(resolve => {const spark = new SparkMD5.ArrayBuffer()// ...计算逻辑})
}// 3. 并发控制上传
async function uploadWithConcurrency(chunks, max = 3) {const pool = new Set()for (let i = 0; i < chunks.length; i++) {const task = uploadChunk(chunks[i], i)pool.add(task)task.finally(() => pool.delete(task))if (pool.size >= max) {await Promise.race(pool)}}
}
6. 虚拟列表(不定高实现)
核心算法思路
class VirtualList {constructor(container, items, itemHeightEstimator) {this.container = containerthis.items = itemsthis.estimatedHeight = itemHeightEstimatorthis.positions = this.calculatePositions()}calculatePositions() {const positions = []let top = 0for (let i = 0; i < this.items.length; i++) {positions.push({top,bottom: top + this.estimatedHeight(this.items[i]),height: this.estimatedHeight(this.items[i])})top += this.estimatedHeight(this.items[i])}return positions}// 动态调整位置adjustPositions(startIndex, measuredHeight) {const diff = measuredHeight - this.positions[startIndex].heightif (diff !== 0) {this.positions[startIndex].height = measuredHeightthis.positions[startIndex].bottom += difffor (let i = startIndex + 1; i < this.positions.length; i++) {this.positions[i].top += diffthis.positions[i].bottom += diff}}}getVisibleItems(scrollTop, containerHeight) {// 二分查找可见区域const startIndex = this.binarySearch(this.positions, scrollTop)const endIndex = this.binarySearch(this.positions, scrollTop + containerHeight)return {startIndex,endIndex,visibleItems: this.items.slice(startIndex, endIndex + 1)}}
}
7. 防抖和节流
// 防抖:连续触发只执行最后一次
function debounce(fn, delay) {let timer = nullreturn function(...args) {clearTimeout(timer)timer = setTimeout(() => fn.apply(this, args), delay)}
}// 节流:连续触发中每隔一段时间执行一次
function throttle(fn, delay) {let lastTime = 0return function(...args) {const now = Date.now()if (now - lastTime >= delay) {fn.apply(this, args)lastTime = now}}
}
8. 垂直水平居中
Flexbox方案(推荐)
.container {display: flex;justify-content: center;align-items: center;height: 100vh;
}
Grid方案
.container {display: grid;place-items: center;height: 100vh;
}
传统定位方案
.container {position: relative;height: 100vh;
}.centered {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);
}
9. Webpack生命周期钩子
常用钩子分类
- 编译阶段:compile、make、emit
- 优化阶段:optimize、afterCompile
- 输出阶段:emit、afterEmit
- 整体生命周期:beforeRun、run、watchRun、done
插件开发示例
class MyPlugin {apply(compiler) {compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {// 生成操作callback()})compiler.hooks.done.tap('MyPlugin', stats => {console.log('编译完成!')})}
}
10. Vite热更新原理
基于ES Module的快速HMR
// 1. 依赖预构建
// 使用esbuild将CommonJS模块转换为ESM// 2. 按需编译
// 浏览器请求时实时编译,无需打包整个应用// 3. HMR流程
// - 文件修改时,Vite服务器接收通知
// - 通过WebSocket向客户端发送更新消息
// - 客户端动态导入更新模块,替换旧模块
11. Vue的nextTick
实现原理
const callbacks = []
let pending = falsefunction nextTick(cb) {callbacks.push(cb)if (!pending) {pending = true// 优先级:Promise > MutationObserver > setImmediate > setTimeoutPromise.resolve().then(flushCallbacks)}
}function flushCallbacks() {pending = falseconst copies = callbacks.slice(0)callbacks.length = 0for (let i = 0; i < copies.length; i++) {copies}
}
12. SSR(服务端渲染)
核心优势
- 更好的SEO:搜索引擎可以直接抓取渲染好的内容
- 更快的首屏加载:减少白屏时间
- 更好的性能体验:特别是对于慢网络环境
实现要点
// 服务端
app.get('*', (req, res) => {const app = createApp()const html = renderToString(app)res.send(`<html><body>${html}</body><script src="/client.js"></script></html>`)
})// 客户端激活
createApp().mount('#app')
💡 面试准备建议
- 理解原理而非死记硬背:每个问题都要能说出"为什么"
- 结合实际项目经验:准备具体的实战案例
- 关注性能优化:大文件上传、虚拟列表等都是性能相关
- 掌握现代工具链:Vite、Webpack、SSR等都要了解
这些题目覆盖了前端工程师需要掌握的核心知识点,深入理解这些问题将为你的面试打下坚实基础。