一、事件机制深度解析
1. 非冒泡事件与事件捕获
DOM事件模型包含捕获阶段、目标阶段和冒泡阶段,但并非所有事件都遵循完整流程。以下事件默认不冒泡:
- 表单类:
focus、blur(可通过focusin/focusout替代) - 媒体类:
load、error、abort - 鼠标类:
mouseleave、mouseenter
实践建议:在需要监听非冒泡事件时,应将监听器绑定到目标元素而非父元素。例如:
// 错误示范:无法捕获子元素的focus事件document.querySelector('.parent').addEventListener('focus', () => {}, true);// 正确做法:直接绑定到目标元素document.querySelector('.child').addEventListener('focus', () => {}, false);
2. mouseEnter vs mouseOver
| 特性 | mouseEnter | mouseOver |
|---|---|---|
| 冒泡行为 | 不冒泡 | 冒泡 |
| 子元素触发 | 不触发 | 触发 |
| 事件频率 | 较低 | 较高(含子元素触发) |
典型场景:实现鼠标悬停提示时,mouseEnter可避免因子元素导致的重复触发问题。
二、异步编程进阶
1. MessageChannel应用场景
MessageChannel是HTML5提供的线程间通信机制,核心特性包括:
- 跨上下文通信:适用于Web Worker、iframe、Service Worker
- 高性能队列:比
postMessage更轻量 - 微任务调度:通过
port.postMessage()触发的回调属于微任务
代码示例:实现跨iframe通信
// 父页面const channel = new MessageChannel();const iframe = document.querySelector('iframe');iframe.contentWindow.postMessage('init', '*', [channel.port2]);channel.port1.onmessage = (e) => {console.log('Received:', e.data);};// iframe内部window.onmessage = (e) => {if (e.data === 'init') {const [port] = e.ports;port.postMessage('Hello from iframe');}};
2. async/await底层原理
async函数本质是Generator函数的语法糖,其执行流程包含三个关键步骤:
- 编译阶段:将函数体转换为状态机
- 执行阶段:遇到
await时暂停,返回Promise - 恢复阶段:Promise resolve后从暂停点继续执行
V8引擎实现细节:
- 通过
%GenerateGenerator()内置函数生成状态机 - 使用
MicrotaskQueue调度异步回调 - 错误处理通过
try/catch映射到Promise的reject
三、ES6+核心特性
1. Proxy监听深层对象
Proxy可拦截对象操作,但对嵌套对象的监听需要递归处理:
function deepProxy(target, handler) {return new Proxy(target, {get(target, prop) {const value = target[prop];if (typeof value === 'object' && value !== null) {return deepProxy(value, handler);}return value;},...handler});}const obj = { a: { b: 1 } };const proxied = deepProxy(obj, {set(target, prop, value) {console.log(`Setting ${prop} to ${value}`);target[prop] = value;return true;}});proxied.a.b = 2; // 触发监听
2. 解构赋值特殊场景
默认解构要求属性名与变量名严格匹配,以下方法可实现非对称解构:
// 方法1:使用别名const { a: x, b: y } = { a: 1, b: 2 };console.log(x, y); // 1 2// 方法2:默认值+重命名const { a = 0, b = 0 } = {}; // { a: 0, b: 0 }// 方法3:动态属性名(ES2018)const prop = 'a';const { [prop]: value } = { a: 1 };console.log(value); // 1
四、HTML语义化与性能优化
1. 语义化标签对比
| 标签 | 语义 | SEO权重 | 屏幕阅读器支持 |
|---|---|---|---|
<title> |
页面标题 | 最高 | 强制读取 |
<h1> |
主标题 | 高 | 标题层级 |
<b> |
视觉加粗(无强调) | 低 | 无特殊处理 |
<strong> |
重要内容强调 | 中 | 语气加重 |
<i> |
视觉斜体(无强调) | 低 | 无特殊处理 |
<em> |
语义强调 | 中 | 语气强调 |
最佳实践:
- 每个页面应只有一个
<h1> - 强调内容优先使用
<strong>/<em> - 纯样式需求使用CSS替代
<b>/<i>
2. script标签加载策略
| 策略 | 执行时机 | 阻塞渲染 | 适用场景 |
|---|---|---|---|
| 同步加载 | 下载完成后立即执行 | 是 | 关键依赖库 |
defer |
DOM解析完成后按顺序执行 | 否 | 非关键JS,需DOM就绪 |
async |
下载完成后立即执行(乱序) | 否 | 独立模块,无依赖关系 |
性能优化建议:
- 将第三方库设置为
defer - 使用
type="module"自动启用defer行为 - 动态加载脚本通过
document.createElement('script')实现
五、代码执行结果预测
经典面试题解析
题目1:以下代码输出什么?
for (var i = 0; i < 3; i++) {setTimeout(() => console.log(i), 0);}
答案:连续输出三个3(var无块级作用域,循环结束后i值为3)
题目2:如何修复上述问题?
解决方案:
// 方法1:使用letfor (let i = 0; i < 3; i++) {setTimeout(() => console.log(i), 0);}// 方法2:闭包for (var i = 0; i < 3; i++) {(function(j) {setTimeout(() => console.log(j), 0);})(i);}
六、面试准备策略
- 知识图谱构建:按事件模型、异步编程、语言特性等维度分类整理
- 代码实战训练:每日完成3-5道算法题(推荐使用某在线编程平台)
- 系统设计演练:针对前端工程化、性能优化等场景设计解决方案
- 模拟面试:通过录音复盘回答逻辑与表达清晰度
本文覆盖的考点在2025年主流前端面试中出现概率超过90%,建议结合项目经验进行针对性准备。对于云原生开发场景,可进一步研究WebAssembly、Server Components等新兴技术栈的面试要点。