1. 前端面试核心知识点解析
作为一名经历过多次大厂面试的前端工程师,我深知面试官最常考察的几个核心知识点。这些内容看似基础,但能准确回答并手写代码的候选人往往不到一半。今天我就结合自己的面试经验和实际项目应用,详细拆解这些必考知识点。
1.1 手写防抖与节流函数
防抖(debounce)和节流(throttle)是前端性能优化的基础技术,也是面试高频考点。很多候选人能说出概念,但手写实现时常常漏洞百出。
防抖的核心实现:
javascript复制function debounce(fn, delay) {
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
关键点:每次触发都清除之前的定时器,确保连续触发时只有最后一次会执行
节流的两种实现方式:
时间戳版(立即执行):
javascript复制function throttle(fn, delay) {
let last = 0
return function(...args) {
const now = Date.now()
if (now - last >= delay) {
fn.apply(this, args)
last = now
}
}
}
定时器版(延迟执行):
javascript复制function throttle(fn, delay) {
let timer = null
return function(...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay)
}
}
}
实际应用场景对比:
- 防抖:搜索框输入联想、窗口resize事件
- 节流:滚动加载、按钮频繁点击
避坑指南:面试时经常会被问到两者区别。简单来说,防抖是"多次触发只执行最后一次",节流是"每隔一段时间执行一次"。实际项目中,我推荐使用lodash的实现,它结合了两种方式的优点。
1.2 前端缓存机制详解
前端缓存分为强制缓存和协商缓存,理解它们的区别对性能优化至关重要。
强制缓存(强缓存):
- 通过Cache-Control和Expires头控制
- 状态码:200 (from memory/disk cache)
- 优先级:Cache-Control > Expires
http复制Cache-Control: max-age=31536000
Expires: Wed, 21 Oct 2025 07:28:00 GMT
协商缓存(弱缓存):
- 通过Last-Modified/If-Modified-Since和ETag/If-None-Match控制
- 状态码:304 (Not Modified)
- 优先级:ETag > Last-Modified
缓存策略最佳实践:
- 静态资源:设置长期强缓存(如1年),通过文件名哈希实现更新
- HTML文件:禁用缓存或设置短时间缓存
- API接口:通常禁用缓存或使用协商缓存
经验分享:在Webpack配置中,我们通常会给输出文件名添加[contenthash],这样内容变化时文件名会改变,可以充分利用强缓存。我曾遇到过因为缓存配置不当导致用户一直看到旧版本的bug,后来通过完善的缓存策略彻底解决了这个问题。
2. JavaScript核心知识点
2.1 数组与字符串常用API
数组高频方法:
- 改变原数组:push/pop/shift/unshift/splice/sort/reverse
- 不改变原数组:slice/concat/map/filter/reduce
- ES6新增:find/findIndex/includes/fill/flat
字符串常用操作:
- 基础:slice/substr/substring/indexOf/includes
- ES6:startsWith/endsWith/repeat/padStart/padEnd
- 正则相关:match/search/replace
ES6重要新特性:
- 变量声明:let/const
- 箭头函数:() => {}
- 解构赋值:const {a, b} = obj
- 模板字符串:
Hello ${name} - 扩展运算符:...arr
- Promise与async/await
- 模块化:import/export
- Class语法糖
编码技巧:面试时经常会被要求手写数组方法。比如实现一个map函数:
javascript复制Array.prototype.myMap = function(fn) {
const result = []
for (let i = 0; i < this.length; i++) {
result.push(fn(this[i], i, this))
}
return result
}
2.2 JavaScript继承实现方式
JavaScript有多种继承方式,面试常考的是它们的区别和实现原理。
1. 原型链继承:
javascript复制function Parent() {
this.name = 'parent'
}
Parent.prototype.say = function() {
console.log(this.name)
}
function Child() {}
Child.prototype = new Parent()
问题:所有实例共享引用属性,无法向父类传参
2. 构造函数继承:
javascript复制function Child() {
Parent.call(this)
}
问题:无法继承父类原型上的方法
3. 组合继承(最常用):
javascript复制function Child() {
Parent.call(this) // 第二次调用Parent
}
Child.prototype = new Parent() // 第一次调用Parent
Child.prototype.constructor = Child
问题:父类构造函数被调用两次
4. 寄生组合继承(最佳方案):
javascript复制function Child() {
Parent.call(this)
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
5. ES6 Class继承:
javascript复制class Child extends Parent {
constructor() {
super()
}
}
面试技巧:当被问到继承时,建议从原型链讲起,逐步引出各种继承方式的优缺点,最后提到ES6的class只是语法糖,本质上还是基于原型链。我曾因为能清晰解释这个知识点而获得面试官的高度评价。
3. 深拷贝与浅拷贝
3.1 概念区分
- 浅拷贝:只复制第一层属性,引用类型共享内存地址
- 深拷贝:完全复制所有层级,新对象与原对象完全独立
浅拷贝实现方式:
javascript复制// 方式1:Object.assign
const newObj = Object.assign({}, obj)
// 方式2:扩展运算符
const newObj = {...obj}
// 方式3:数组slice
const newArr = arr.slice()
3.2 深拷贝实现
基础版(不考虑特殊情况):
javascript复制function deepClone(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj
}
const result = Array.isArray(obj) ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key])
}
}
return result
}
完善版(考虑各种边界条件):
javascript复制function deepClone(obj, hash = new WeakMap()) {
if (obj === null) return null
if (typeof obj !== 'object') return obj
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
if (hash.has(obj)) return hash.get(obj)
const cloneObj = new obj.constructor()
hash.set(obj, cloneObj)
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], hash)
}
}
return cloneObj
}
其他深拷贝方式:
- JSON.parse(JSON.stringify(obj))
- 问题:无法处理函数、Symbol、循环引用
- 使用第三方库如lodash的_.cloneDeep
实战经验:在项目中处理复杂对象时,我遇到过JSON方法导致的函数丢失问题。后来改用递归实现解决了这个问题。面试时手写深拷贝要注意处理循环引用,可以使用WeakMap来存储已拷贝对象。
4. 面试准备建议
根据我的面试经验,除了掌握这些技术点外,还需要注意:
- 理解原理而非死记硬背:面试官常会追问"为什么这样实现"
- 能分析时间/空间复杂度:特别是手写算法时
- 准备项目案例:每个知识点最好能结合实际项目经验
- 注意代码规范:变量命名、边界条件处理等细节
- 练习白板编程:有些公司会要求在纸上或白板上写代码
我曾因为在一个问题上回答"这个我在项目中没有实际用过"而失去机会。后来我养成了对每个知识点都准备一个实际案例的习惯,通过率明显提高。
前端技术更新很快,但这些基础知识点经久不衰。建议定期复习并动手实践,真正理解背后的原理,而不仅仅是为了应付面试。在最近的项目中,我正是靠着扎实的基础,快速解决了一个复杂的性能优化问题。