代码题目👉
一、计算最长不重复子串
实现思路:
使用滑动窗口(双指针)和哈希表优化时间复杂度。右指针扩展窗口,遇到重复字符时,左指针跳跃到重复字符的下一位,同时用哈希表记录字符的最新位置。
JavaScript实现:
function longestSubstring(s) {
let map = new Map(), max = 0, left = 0;
for (let right = 0; right < s.length; right++) {
const c = s[right];
if (map.has(c) && map.get(c) >= left) {
left = map.get(c) + 1; // 左边界跳跃到重复字符后
}
map.set(c, right); // 更新字符的最新位置
max = Math.max(max, right - left + 1);
}
return max;
}
复杂度:时间复杂度 O(n),空间复杂度 O(字符集大小)(如ASCII字符集为常数级)。
二、实现防抖函数
核心逻辑:在事件触发后等待固定时间,若期间再次触发则重置计时,最终只执行最后一次触发对应的函数。
JavaScript实现:
function debounce(fn, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
// 示例:输入框搜索防抖
const inputEl = document.getElementById('search-input');
const debouncedSearch = debounce((query) => {
console.log('Search:', query);
}, 500);
inputEl.addEventListener('input', (e) => debouncedSearch(e.target.value));
三、实现管道函数 pipe
功能:将多个函数按顺序组合,前一个函数的返回值作为后一个的输入参数。
JavaScript实现:
function pipe(funcs) {
return function (initialValue) {
return funcs.reduce((acc, fn) => fn(acc), initialValue);
};
}
// 示例:计算 (x*2 + 3)*4
const times = (n) => (x) => x * n;
const plus = (n) => (x) => x + n;
const pipeline = pipe([times(2), plus(3), times(4)]);
console.log(pipeline(5)); // 输出:(5*2+3)*4 = 52
四、解析URL
方法:使用浏览器原生 URL 对象和 URLSearchParams API,可高效解析协议、路径、查询参数等。
JavaScript实现:
function parseUrl(urlString) {
const url = new URL(urlString);
return {
protocol: url.protocol, // 协议(如 "https:")
hostname: url.hostname, // 域名(如 "example.com")
pathname: url.pathname, // 路径(如 "/path")
searchParams: Object.fromEntries(url.searchParams) // 查询参数对象
};
}
// 示例解析
const result = parseUrl("https://example.com/path?name=John&age=30");
console.log(result.searchParams); // 输出:{ name: "John", age: "30" }
关键点总结
1. 滑动窗口优化是解决最长不重复子串的最优方案,避免暴力法的 O(n²) 复杂度。
2. 防抖函数通过延迟执行减少高频事件触发的资源消耗,适用于搜索联想、窗口调整等场景。
3. 管道函数通过函数组合实现声明式编程,提升代码可读性。
4. URL解析推荐使用原生API,兼容性不足时可改用字符串分割或正则表达式。
手撕题目知识框架✍️
一、JavaScript基础与原理
1. 原型链与继承
• 手写 new 运算符实现
• 实现 Object.create() 的简化版
• 继承方式的代码实现(如寄生组合继承)
2. 异步与事件循环
• 实现 Promise.all/Promise.race
• 手写 async/await 的Generator模拟
• 事件循环顺序分析题(宏任务、微任务)
3. 闭包与作用域
• 闭包陷阱场景题(如循环中延迟打印i的值)
• 柯里化(Currying)函数实现
二、算法与数据结构
1. 数组与字符串处理
• 扁平化数组(flatten)的多维处理
• 最长公共前缀(LeetCode 14)
• 实现模板字符串解析(类似${data}替换)
2. 树与链表操作
• 二叉树层序遍历(BFS)
• 反转链表(迭代/递归)
• 虚拟DOM树的Diff算法简化实现
三、前端框架相关
1. React/Vue原理实现
• 实现简易版 useState(状态管理)
• 虚拟DOM转真实DOM的渲染函数
• 响应式数据劫持(类似Vue 2的 Object.defineProperty)
2. DOM与事件
• 事件委托实现动态元素点击监听
• 拖拽组件的核心逻辑(mousedown/mousemove事件处理)
• 实现防抖(Debounce)与节流(Throttle)
四、工程化与网络
1. 模块化与打包
• 实现 require 的简化版(CommonJS模块加载)
• 按需加载(Dynamic Import)的Promise封装
2. HTTP与浏览器
• 手写 XMLHttpRequest 请求封装
• Cookie与LocalStorage的读写工具函数
• 跨域解决方案代码(如JSONP实现)
五、综合实战题
1. 组件设计题
• 实现一个可配置的模态框组件(支持动画、遮罩层)
• 封装表单校验工具(支持异步校验规则)
2. 性能优化场景
• 长列表虚拟滚动(Virtual Scroll)核心逻辑
• 图片懒加载的IntersectionObserver实现
考察重点与建议
1. 代码规范:变量命名、边界条件处理、可读性
2. 思维表达:解题思路的口头或注释说明
3. 底层原理:对JavaScript引擎、框架设计理念的理解。
一、JavaScript基础与原理
1. 手写 new 运算符
function myNew(constructor, ...args) {
const obj = Object.create(constructor.prototype);
const result = constructor.apply(obj, args);
return result instanceof Object ? result : obj;
}
考察点:原型链继承、构造函数逻辑。
扩展:可结合寄生组合继承实现类继承场景。
2. 实现 Promise.all
function myPromiseAll(promises) {
return new Promise((resolve, reject) => {
const results = [];
let completed = 0;
promises.forEach((p, i) => {
Promise.resolve(p)
.then(res => {
results[i] = res;
if (++completed === promises.length) resolve(results);
})
.catch(reject);
});
});
}
应用场景:并发请求处理、批量数据加载。
二、算法与数据结构
1. 数组分块(Chunk)
根据搜索结果中提到的真题,实现数组分块:
function chunk(arr, size) {
const res = [];
for (let i = 0; i < arr.length; i += size) {
res.push(arr.slice(i, i + size));
}
return res;
}
// 测试:chunk(['a','b','c','d'], 2) → [['a','b'], ['c','d']]
考察点:数组操作、边界条件处理。
2. 文件路径转树形结构
真题高频题:
function buildTree(paths) {
const tree = {};
paths.forEach(path => {
const parts = path.split('/');
let current = tree;
parts.forEach(part => {
if (!current[part]) current[part] = {};
current = current[part];
});
});
return tree;
}
// 测试:buildTree(['src/index.js', 'src/utils.js']) → { src: { 'index.js': {}, 'utils.js': {} } }
关键点:递归或迭代处理层级结构、对象引用。
三、前端框架与工程化
1. 实现简易 useState
let state;
function useState(initialValue) {
state = state ?? initialValue;
const setState = (newValue) => {
state = typeof newValue === 'function' ? newValue(state) : newValue;
// 触发重渲染(此处简化为直接更新)
};
return [state, setState];
}
扩展:结合虚拟DOM的Diff算法实现更完整的状态更新逻辑。
2. 防抖与节流
// 防抖
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 节流
function throttle(fn, interval) {
let last = 0;
return (...args) => {
const now = Date.now();
if (now - last >= interval) {
fn.apply(this, args);
last = now;
}
};
}
应用场景:搜索联想输入、滚动事件优化。
四、综合实战题
1. 虚拟滚动核心逻辑
function virtualScroll(items, containerHeight, itemHeight) {
const visibleCount = Math.ceil(containerHeight / itemHeight);
let startIndex = 0;
return function updateScroll(scrollTop) {
const newStart = Math.floor(scrollTop / itemHeight);
startIndex = Math.max(0, newStart - 2); // 预加载2项
return items.slice(startIndex, startIndex + visibleCount + 4);
};
}
优化点:动态计算渲染区间、DOM复用。
高频考察方向总结(根据补充)
1. CSS布局
• 左侧定宽右侧弹性布局:display: flex; + flex: 1;
2. TypeScript
• 类型推断与接口设计:interface User { id: number; name: string; }
3. HTTP/TCP
• 三次握手、状态码(如304缓存)、HTTP/2多路复用。
投递建议与准备资源
1. 内推通道:通过官方内推链接(https://u.alipay.cn/_2YehV2IUVPjoPN3pYfcpzf)投递技术类岗位。
2. 重点复习:根据真题,强化 数组操作、树形结构处理、框架原理手写。
3. 模拟训练:使用在线OJ平台(如LeetCode、CodeFun)练习高频算法题。