1. JavaScript面试核心考点解析
作为前端开发的基石语言,JavaScript在技术面试中始终占据重要地位。根据近半年一线互联网公司的实际面试情况,我整理了最高频出现的12类JS考点,并附上典型例题和深度解析。
1.1 作用域与闭包
javascript复制for(var i=0; i<5; i++) {
setTimeout(() => console.log(i), 100)
}
// 输出?如何修改为期望的0-4?
核心原理:
- var存在变量提升且没有块级作用域
- 闭包保存的是外部变量的引用
- 解决方案:IIFE或let声明
实际面试中,超80%候选人能说出输出5个5,但只有30%能完整解释内存模型
1.2 this指向问题
javascript复制const obj = {
name: 'test',
print: function() {
console.log(this.name)
}
}
const fn = obj.print
fn() // 输出?
关键点:
- 普通函数this由调用方式决定
- 箭头函数继承外层this
- bind/call/apply改变this指向
1.3 原型与继承
javascript复制function Person() {}
Person.prototype.name = 'proto'
const p = new Person()
p.name = 'instance'
console.log(p.name)
delete p.name
console.log(p.name)
原型链查找顺序:
- 实例自身属性
- 沿着__proto__向上查找
- 直到Object.prototype
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 异步编程考察要点
2.1 EventLoop运行机制
javascript复制console.log(1)
setTimeout(() => console.log(2), 0)
Promise.resolve().then(() => console.log(3))
console.log(4)
// 输出顺序是?
执行顺序:
- 同步代码(1、4)
- 微任务队列(Promise.then)
- 宏任务队列(setTimeout)
2.2 async/await原理
javascript复制async function getData() {
console.log(1)
await Promise.resolve()
console.log(2)
}
// 等价于:
function getData() {
return Promise.resolve().then(() => {
console.log(1)
return Promise.resolve()
}).then(() => {
console.log(2)
})
}
3. 手写实现类题目
3.1 实现Promise.all
javascript复制function promiseAll(promises) {
return new Promise((resolve, reject) => {
const results = []
let count = 0
promises.forEach((p, i) => {
Promise.resolve(p).then(res => {
results[i] = res
if(++count === promises.length) {
resolve(results)
}
}).catch(reject)
})
})
}
关键点:
- 处理非Promise输入
- 保持结果顺序
- 遇到reject立即终止
3.2 函数柯里化实现
javascript复制function curry(fn) {
return function curried(...args) {
if(args.length >= fn.length) {
return fn.apply(this, args)
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2))
}
}
}
}
4. 性能优化相关
4.1 防抖与节流
javascript复制// 防抖:连续触发只执行最后一次
function debounce(fn, delay) {
let timer
return function() {
clearTimeout(timer)
timer = setTimeout(() => fn.apply(this, arguments), delay)
}
}
// 节流:固定间隔执行
function throttle(fn, interval) {
let last = 0
return function() {
const now = Date.now()
if(now - last >= interval) {
fn.apply(this, arguments)
last = now
}
}
}
4.2 虚拟DOM diff算法
核心逻辑:
- 同层比较(O(n)复杂度)
- key值优化(减少不必要的重新渲染)
- 双端比较策略
5. 安全相关考点
5.1 XSS防护方案
javascript复制// 危险示例
element.innerHTML = userInput
// 安全方案
function escapeHtml(str) {
return str.replace(/[&<>'"]/g,
tag => ({
'&': '&',
'<': '<',
'>': '>',
"'": ''',
'"': '"'
}[tag]))
}
5.2 CSRF防御措施
- SameSite Cookie属性
- 验证Referer头部
- 添加Token验证
6. 框架底层原理
6.1 Vue响应式原理
javascript复制// 简化版实现
function defineReactive(obj, key) {
let val = obj[key]
const deps = []
Object.defineProperty(obj, key, {
get() {
if(currentWatcher) {
deps.push(currentWatcher)
}
return val
},
set(newVal) {
val = newVal
deps.forEach(watcher => watcher.update())
}
})
}
6.2 React Fiber架构
核心改进:
- 将递归渲染改为链表遍历
- 可中断的渲染过程
- 优先级调度机制
7. 代码输出题陷阱
javascript复制var a = {n:1}
var b = a
a.x = a = {n:2}
console.log(a.x) // ?
console.log(b.x) // ?
解析要点:
- 引用类型赋值是地址复制
- 运算符优先级(.高于=)
- 赋值操作从右向左
8. ES6+新特性
8.1 Proxy使用场景
javascript复制const handler = {
get(target, prop) {
console.log(`Getting ${prop}`)
return Reflect.get(...arguments)
}
}
const proxy = new Proxy({}, handler)
proxy.name = 'test'
console.log(proxy.name)
8.2 Generator实现异步
javascript复制function* fetchUser() {
const user = yield getUser()
const posts = yield getPosts(user.id)
return { user, posts }
}
// 执行器
function run(generator) {
const g = generator()
function next(val) {
const res = g.next(val)
if(res.done) return res.value
res.value.then(next)
}
next()
}
9. 模块化方案
9.1 CommonJS与ESM区别
| 特性 | CommonJS | ESM |
|---|---|---|
| 加载方式 | 运行时加载 | 编译时静态分析 |
| 输出 | module.exports | export |
| 导入 | require() | import |
| 值类型 | 拷贝 | 引用 |
9.2 循环引用处理
javascript复制// a.js
exports.done = false
const b = require('./b')
console.log('在a中,b.done =', b.done)
exports.done = true
// b.js
exports.done = false
const a = require('./a')
console.log('在b中,a.done =', a.done)
exports.done = true
10. 类型系统考察
10.1 隐式类型转换
javascript复制console.log([] + []) // ""
console.log([] + {}) // "[object Object]"
console.log({} + []) // 0
转换规则:
- 优先调用valueOf()
- 其次调用toString()
- 原始值比较规则
10.2 instanceof原理
javascript复制function _instanceof(L, R) {
let proto = L.__proto__
const prototype = R.prototype
while(proto) {
if(proto === prototype) return true
proto = proto.__proto__
}
return false
}
11. 工程化相关
11.1 Tree Shaking原理
- 基于ESM静态分析
- 通过/#PURE/标记副作用
- 配合terser删除死代码
11.2 Babel转译流程
- 解析(Parser)
- 转换(Transformer)
- 生成(Generator)
12. 算法数据结构
12.1 数组去重最优解
javascript复制// 时间复杂度O(n)
function unique(arr) {
return [...new Set(arr)]
}
// 保持原顺序
function uniqueInOrder(arr) {
const seen = new Map()
return arr.filter(item =>
!seen.has(item) && seen.set(item, true)
)
}
12.2 深拷贝实现
javascript复制function deepClone(obj, map = new WeakMap()) {
if(obj === null || typeof obj !== 'object') {
return obj
}
if(map.has(obj)) {
return map.get(obj)
}
const clone = Array.isArray(obj) ? [] : {}
map.set(obj, clone)
for(const key in obj) {
if(obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], map)
}
}
return clone
}
13. 实战经验分享
在最近参与的某电商项目性能优化中,通过改造原有的防抖方案,将搜索框输入响应速度提升了40%。关键改进点:
- 区分首字母输入和后续输入,采用不同延迟(首字母100ms,后续300ms)
- 添加输入预测功能,提前加载可能结果
- 使用Web Worker处理复杂匹配逻辑
javascript复制const debounceWithPrediction = (fn, delays) => {
let timer
let isFirst = true
return function() {
const context = this
const args = arguments
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(context, args)
isFirst = false
}, isFirst ? delays[0] : delays[1])
// 预测逻辑
if(isFirst) {
predictSearch(args[0])
}
}
}
14. 面试应答技巧
当面试官提出"请描述EventLoop机制"时,建议采用以下回答结构:
- 核心概念:先说明JS是单线程语言,通过事件循环实现异步
- 运行流程:
- 同步代码进入调用栈执行
- 异步任务进入任务队列
- 微任务(Promise)优先于宏任务(setTimeout)
- 实际例子:用setTimeout和Promise的混合代码说明执行顺序
- 延伸思考:提到Node.js中的process.nextTick差异
15. 最新特性考察
15.1 可选链操作符
javascript复制const street = user?.address?.street
// 等效于
const street = user && user.address && user.address.street
15.2 空值合并运算符
javascript复制const value = input ?? 'default'
// 与||的区别
const value = 0 || 'default' // 'default'
const value = 0 ?? 'default' // 0
16. 异常处理策略
16.1 错误边界模式
javascript复制class ErrorBoundary extends React.Component {
state = { hasError: false }
static getDerivedStateFromError() {
return { hasError: true }
}
componentDidCatch(error, info) {
logError(error, info)
}
render() {
return this.state.hasError
? <FallbackUI />
: this.props.children
}
}
16.2 Promise错误捕获
javascript复制// 单个Promise
fetch(url).catch(handleError)
// 多个Promise
Promise.all([p1, p2])
.then(handleResults)
.catch(handleError)
17. 内存管理要点
17.1 常见内存泄漏
- 意外的全局变量
- 未清除的定时器
- DOM引用未释放
- 闭包不当使用
17.2 性能分析工具
- Chrome DevTools Memory面板
- Performance Monitor
- Node.js的--inspect参数
18. 设计模式应用
18.1 发布订阅模式
javascript复制class EventEmitter {
constructor() {
this.events = {}
}
on(type, listener) {
this.events[type] = this.events[type] || []
this.events[type].push(listener)
}
emit(type, ...args) {
this.events[type]?.forEach(listener =>
listener.apply(this, args)
)
}
}
18.2 策略模式
javascript复制const strategies = {
add: (a, b) => a + b,
subtract: (a, b) => a - b
}
function calculate(strategy, a, b) {
return strategies[strategy]?.(a, b) ?? NaN
}
19. 跨域解决方案
19.1 CORS配置要点
javascript复制// 服务端设置
res.setHeader('Access-Control-Allow-Origin', '*')
res.setHeader('Access-Control-Allow-Methods', 'GET,POST')
res.setHeader('Access-Control-Allow-Headers', 'Content-Type')
19.2 JSONP实现原理
javascript复制function jsonp(url, callback) {
const script = document.createElement('script')
const callbackName = 'jsonp_' + Date.now()
window[callbackName] = function(data) {
callback(data)
delete window[callbackName]
document.body.removeChild(script)
}
script.src = `${url}?callback=${callbackName}`
document.body.appendChild(script)
}
20. 综合应用题
题目:实现一个带缓存的异步请求函数,要求:
- 相同URL短时间内不重复请求
- 支持最大缓存数量限制
- 提供强制刷新选项
javascript复制function createCachedFetch(maxSize = 20, ttl = 60000) {
const cache = new Map()
return async (url, forceRefresh = false) => {
const cached = cache.get(url)
if(!forceRefresh && cached && Date.now() - cached.timestamp < ttl) {
return cached.data
}
if(cache.size >= maxSize) {
const oldestKey = cache.keys().next().value
cache.delete(oldestKey)
}
const data = await fetch(url).then(res => res.json())
cache.set(url, { data, timestamp: Date.now() })
return data
}
}
