高级前端面试题及答案(最新版)

1,563 阅读6分钟

高级前端面试题及答案(最新版)

JavaScript 深入

1. 解释 Event Loop 机制,包括宏任务和微任务的区别

答案: Event Loop 是 JavaScript 实现异步的核心机制,它由以下部分组成:

  1. 调用栈(Call Stack):同步代码的执行栈
  2. 任务队列(Task Queue):存放宏任务
  3. 微任务队列(Microtask Queue):存放微任务

执行顺序:

  • 执行同步代码(属于第一个宏任务)
  • 执行当前宏任务产生的所有微任务
  • 执行下一个宏任务
  • 循环...

区别

宏任务(Macrotask)微任务(Microtask)
示例setTimeout, setInterval, I/OPromise.then, MutationObserver
执行时机Event Loop的每个循环执行一个在每个宏任务结束后立即全部执行
APIRun by host environmentRun by JS engine

2. Proxy/Reflect API的高级应用场景

答案: Proxy可以用于:

// 1. API请求拦截器
const apiHandler = {
    get(target, prop) {
        return async (...args) => {
            console.log(`Calling ${prop} with`, args);
            return target[prop](...args).catch(err => {
                //统一错误处理
                sentry.captureException(err);
                throw err;
            });
        };
    }
};

//2.响应式数据实现(Vue3原理)
function reactive(obj) {
    return new Proxy(obj, {
        get(target, key) {
            track(target, key); //依赖收集
            return Reflect.get(...arguments);
        },
        set(target, key, value) {
            trigger(target, key); //触发更新
            return Reflect.set(...arguments);
        }
    });
}

Reflect的用途:

//1.替代Object上的方法,更函数式
const obj = { foo: 'bar' };
Reflect.has(obj, 'foo'); //替代'foo' in obj

//2.与Proxy配合使用保持默认行为
const proxy = new Proxy(obj, {
    get(target, prop) {
        if(prop === 'secret') return undefined;
        return Reflect.get(...arguments); //保持默认行为
    }
});

React高级特性

###3.React Fiber架构原理

答案: Fiber是React16引入的新协调引擎,核心改进:

  1. 可中断渲染:将渲染工作拆分为多个小单元(fiber节点),每个单元完成后检查剩余时间,没有时间则暂停并让出主线程。

  2. 双缓冲技术:维护两棵fiber树(Current和WorkInProgress),减少直接操作DOM的开销。

  3. 优先级调度:区分不同优先级的更新(如用户交互>数据获取)。

  4. 新的生命周期:划分render阶段(pre-commit phase)和commit阶段。

关键数据结构:

interface FiberNode {
    tag: WorkTag; //组件类型(Function/Class/Host等)
    key: string | null;
    elementType: any;
    stateNode: any; //对应的实例
    
    //链表结构
    return: FiberNode | null; //父节点
    child: FiberNode | null; //第一个子节点
    sibling: FiberNode | null; //兄弟节点
    
    //更新相关 
    memoizedState: any; //hooks链表(Hook会挂载到这里)
    
    //副作用标记(EffectTag)
    flags: Flags;
}

###4.Hooks实现原理及自定义高级Hook示例

实现原理: 1.React通过维护一个"current dispatcher"变量来区分mount/update阶段。 2.Function组件首次渲染时创建hook链表并挂载到fiber.memoizedState上。 3.Hook对象结构:

type Hook = {
    memoizedState: any,     //当前状态值(useState)/effect对象(useEffect)
    baseState: any,
    baseQueue: Update<any>,
    
queue: UpdateQueue<any>,   //待处理的更新队列
    
next: Hook | null          //下一个hook(形成链表)
};

高级Hook示例 - useAsync:

function useAsync(asyncFunction, immediate = true) {
const [status, setStatus] = useState('idle');
const [value, setValue] = useState(null);
const [error, setError] = useState(null);

const execute = useCallback(() =>{
setStatus('pending');
setValue(null);
setError(null);

return asyncFunction()
.then(response =>{
setValue(response);
setStatus('success');
})
.catch(error =>{
setError(error);
setStatus('error');
});
}, [asyncFunction]);

useEffect(() =>{
if (immediate) execute();
}, [execute]);

return { execute, status, value, error };
}

//使用示例:
const { execute }= useAsync(fetchData);
<button onClick={execute}>重新加载</button>

##性能优化专题

###5.Web Worker优化长列表渲染方案

方案代码:

//主线程:
function renderWithWorker(listData){
const worker=new Worker('./listWorker.js');

worker.postMessage({
type:'init',
data:{ items:listData }
});

worker.onmessage=(e)=>{
if(e.data.type==='chunk-ready'){
requestIdleCallback((deadline)=>{
while(deadline.timeRemaining()>0 && e.data.chunk.length){
renderChunk(e.data.chunk.shift());
}
});
}
};
}

//Worker线程(listWorker.js):
self.onmessage=function(e){
if(e.data.type==='init'){
let index=0;
const chunkSize=50;

function processChunk(){
if(index>=e.data.items.length){
self.postMessage({ type:'done' });
return;
}

const chunk=e.data.items.slice(index,
Math.min(index+chunkSize,e.data.items.length));
index+=chunkSize;

self.postMessage({
type:'chunk-ready',
chunk:[chunk] 
});

requestAnimationFrame(processChunk);
}

processChunk();
}
};

关键点说明: 1.Worker处理数据分块避免阻塞主线程UI渲染。 2.requestIdleCallback确保只在浏览器空闲时处理UI更新。 3.chunk大小动态调整可基于设备性能指标。

###6.WebAssembly在前端性能优化的实践案例

典型应用场景及对比:

场景一:图像处理(PDF.js中的色彩转换)

传统JS实现:

function convertRGBtoCMYK(pixels){
for(let i=0;i<pixels.length;i+=4){
let r=pixels[i]/255;
let g=pixels[i+1]/255;
let b=pixels[i+2]/255;

let k=1-Math.max(r,g,b);
pixels[i]=k===1?0:(1-r-k)/(1-k)*255;//C 
pixels[i+1]=k===1?0:(1-g-k)/(1-k)*255;//M 
pixels[i+2]=k===1?0:(1-b-k)/(1-k)*255;//Y 
pixels[i+3]=k*255;//K 
} 
}

WebAssembly版本(Rust):

#[wasm_bindgen]
pub fn convert_rgb_to_cmyk(pixels:&mut[u8]){
for i in (0..pixels.len()).step_by(4){
let r=f64::from(pixels[i])/255.0;
let g=f64::from(pixels[i+1])/255.0;
let b=f64::from(pixels[i+2])/255.0;

let k=1.0-r.max(g).max(b);

pixels[i]=if k==1.0{0}else{((1.0-r-k)/(1.0-k)*255.)as u8}; 
pixels[i+3]=(k*255.)as u8; 

} 
}

性能对比指标:

指标纯JS实现WASM版本
10MB图片处理时间320ms85ms
CPU占用峰值98%45%
内存占用120MB65MB

##TypeScript高级特性

###7.TS类型编程实战:实现Vuex的类型推导

完整类型定义方案:

interface ModuleTree<R>{
[key:string]:Module<R>;
}

interface Module<S,R={}>{
namespaced?:boolean;
state:S; 
getters?:Getters<S,R>;
mutations?:Mutations<S>;
actions?:Actions<S,R>;
modules?:ModuleTree<R>;
}

type GetterReturnType<G>={
[K in keyof G]:G[K] extends(...args:any)=>infer R?R:G[K];
};

type ActionContext<S,R>={
dispatch:Dispatch,
commit:MutationFn,
state:S,
rootState:R,
getters:Getters<S,R>
};

type StoreOptions<S>={
state:S,
getters?:Getters<S,S>,
mutations?:Mutations<S>,
actions?:Actions<S,S>,
modules?:ModuleTree<S>
};

//最终Store类型推导  
class VuexStore<
S,
G extends Getters<S,S>,
M extends Mutations<S>,
A extends Actions<S,S>
>{
constructor(options:{
state:S & ThisType<Readonly<S>>,
getters?:G & ThisType<Readonly<GetterReturnType<G>>>,
mutations?:M & ThisType<void>,
actions?:A & ThisType<void>
}){}

get state():S{return {} as S;}
dispatch:K extends keyof A?A[K]:(...args)=>Promise<any>;
commit:K extends keyof M?Parameters<M[K]>[extends undefined?()=>void:P]> :never;

//动态模块注册  
registerModule<N extends string,M>(path:N[],module:M):void{}
}

使用效果:

const store=new VuexStore({
state:{
count:0  
},
mutations:{
increment(state){  
state.count++;  
}  
},
actions:{
asyncIncrement({commit}){
setTimeout(()=>commit('increment'),100);  
}  
}});

store.commit('increment');//✅正确  
store.commit('unknown');//❌错误提示  

store.dispatch('asyncIncrement');//✅正确返回Promise  

store.state.count.toFixed();//✅自动推导为number类型  

关键点说明: -ThisType控制上下文类型推导路径模板字符串类型与条件类型的深度结合。 -递归类型处理嵌套modules的场景。 -infer关键字提取函数返回值类型。

##框架设计原理

###8.Vue3编译器优化细节解析

编译过程关键优化点:

输入模板:<div><span>{{msg}}</span></div>

传统Vue2编译结果:

with(this){return _c('div',[_c('span',[_v(_s(msg))])])}   

存在的问题:-with语句导致作用域不可静态分析 -全量diff无法跳过静态节点

Vue3优化后输出:

import { createVNode as _createVNode } from "vue"  

export function render(_ctx){  
return (_openBlock(),
_createBlock("div",null,[_createVNode("span",null,_toDisplayString(_ctx.message))]))
}   

核心优化技术:

####PatchFlag标记静态分析结果:

在生成的虚拟DOM节点中添加shapeFlag和patchFlag:

_createVNode("span",null,_toDisplayString(_ctx.message),/*TEXT*/8)

其中8表示只有文本内容会变化。

运行时根据这些标记可以跳过不必要的比较:

if(vnode.patchFlag & PatchFlags.TEXT){   
hostSetElementText(el,vnode.children);   
}else if(!optimized){   
patchChildren(n,c,...);//全量diff   
}   

####Block Tree优化:

通过_openBlock()收集动态子节点形成一个block。在父级变动时可以直接跳过整个静态子树。

####静态提升(HoistStatic):

将纯静态节点提升到渲染函数外部:

原始模板中有多个<footer>Copyright</footer>会被编译为:

const _hoisted=_createVNode("footer",null,"Copyright");   

function render(){   
return [_hoisted,...];   
}   

##工程化体系

###9.Monorepo架构下的前端模块化设计

基于pnpm workspace的现代前端架构方案:

项目结构示例:

monorepo/
├── packages/
│   ├── shared/             #公共库      
│   │   └── package.json    
│   ├── react-components/   #React组件库     
│   │   └── package.json    
│   └── vue-components/     #Vue组件库     
│       └── package.json    
├── apps/
│   ├── admin-web/          #管理系统     
│   │   └── package.json    
│   └── mobile-h5/          #移动端H5      
│       └── package.json    
└── package.json            

核心配置要点:

根package.json配置workspaces:

{
"workspaces":[
"packages/*",
"apps/*"
],
"scripts":{
"build":"pnpm -r run build"
}
}

模块依赖管理策略:

packages/react-components/package.json示例:

{
"name":"@mono/react-components",
"dependencies":{
"@mono/shared":"workspace:*",
"react":"^18"
},
peerDependencies:{
"react-dom":"^18"
}
}

构建工具链集成建议:

esbuild+Turborepo构建加速方案配置(turbo.json):

{ "pipeline":{     
 "build":{       
 "dependsOn":["^build"],       
 "outputs":[".dist/**"]     
 },     
 "test":{       
 "dependsOn":["build"],       
 "inputs":["src/**/*"]     
 }   
 } }  

关键优势分析图表:

传统Multirepo vs Monorepo对比指标对比:

指标项 Multirepo Monorepo(with pnpm)

安装依赖时间 ⏱️25min 🚀90s
跨包重构难度 🔥高 👍低
CI缓存命中率 ❌30% ✅85%
磁盘空间占用 💾15GB 🪶4GB