以下是前端面试中高频手撕题目分类整理,结合字节跳动、得物等大厂真题及代码实现,建议重点掌握:
一、JS核心手写题
- 防抖与节流
字节高频
// 防抖(最后一次触发后执行)
function debounce(fn, delay=500) {
let timer = null;
return (...args) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 节流(固定时间间隔执行)
function throttle(fn, delay=200) {
let flag = true;
return (...args) => {
if (!flag) return;
flag = false;
setTimeout(() => {
fn.apply(this, args);
flag = true;
}, delay);
};
}
- Promise核心
得物高频
// 手写Promise.allSettled(得物真题)
Promise.allSettled = promises => {
return new Promise(resolve => {
const res = [];
let count = 0;
promises.forEach((p, i) => {
Promise.resolve(p).then(
val => res[i] = { status: 'fulfilled', value: val },
err => res[i] = { status: 'rejected', reason: err }
).finally(() => (++count === promises.length) && resolve(res));
});
});
};
二、原型与继承
- 手写instanceof
function myInstanceof(obj, constructor) {
let proto = Object.getPrototypeOf(obj);
const prototype = constructor.prototype;
while (proto) {
if (proto === prototype) return true;
proto = Object.getPrototypeOf(proto);
}
return false;
}
- 手写new操作符
function myNew(Fn, ...args) {
const obj = Object.create(Fn.prototype);
const result = Fn.apply(obj, args);
return result instanceof Object ? result : obj;
}
三、函数与作用域
- call/apply/bind实现
// call(字节真题)
Function.prototype._call = function(context, ...args) {
context = context || window;
const fn = Symbol();
context[fn] = this;
const result = context[fn](...args);
delete context[fn];
return result;
};
四、数据结构与算法
- LRU缓存(字节高频)
class LRUCache {
constructor(capacity) {
this.cache = new Map();
this.capacity = capacity;
}
get(key) {
if (!this.cache.has(key)) return -1;
const val = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, val);
return val;
}
put(key, val) {
this.cache.delete(key);
this.cache.set(key, val);
if (this.cache.size > this.capacity)
this.cache.delete(this.cache.keys().next().value);
}
}
- 深拷贝(字节/得物高频)
function deepClone(obj, hash = new WeakMap()) {
if (typeof obj !== 'object' || obj === null) return obj;
if (hash.has(obj)) return hash.get(obj);
const clone = Array.isArray(obj) ? [] : {};
hash.set(obj, clone);
for (const key in obj) {
if (obj.hasOwnProperty(key))
clone[key] = deepClone(obj[key], hash);
}
return clone;
}
五、框架相关(React/Vue)
- 有效括号问题(字节真题)
// 最长有效括号(动态规划)
function longestValidParentheses(s) {
const dp = new Array(s.length).fill(0);
let max = 0;
for (let i = 1; i < s.length; i++) {
if (s[i] === ')') {
if (s[i-1] === '(') {
dp[i] = (i >= 2 ? dp[i-2] : 0) + 2;
} else if (i - dp[i-1] > 0 && s[i - dp[i-1] -1] === '(') {
dp[i] = dp[i-1] + 2 + (i - dp[i-1] >=2 ? dp[i - dp[i-1] -2] : 0);
}
max = Math.max(max, dp[i]);
}
}
return max;
}
六、高频附加题
数组扁平化
function flatten(arr) { return arr.reduce((acc, cur) => acc.concat(Array.isArray(cur) ? flatten(cur) : cur), []); }
柯里化函数
const curry = fn => judge = (...args) => args.length >= fn.length ? fn(...args) : (...arg) => judge(...args, ...arg);
大厂真题重点标注
公司 | 高频考点 | 真题来源 |
---|---|---|
字节跳动 | LRU缓存、React Fiber、Promise链式调度 | |
得物 | Promise.allSettled、Webpack优化 |
建议结合LeetCode高频题(如有效括号、三数之和)和框架原理(如React Hooks实现)进行扩展练习。更多完整代码和思路可参考:前端面试手撕题整理。