webDevInterviewQuestions/algorithm/05-framework-algorithms.md
2026-01-19 09:43:07 +08:00

261 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 框架相关算法
## 1. 虚拟DOM Diff 算法
> **场景**React/Vue 核心渲染机制、理解为何需要 key 属性、性能优化方向。
> **解决**:直接操作真实 DOM 性能开销大,通过对比新旧虚拟树最小化 DOM 操作。
### 简化版 Diff 实现
```js
function diff(oldVNode, newVNode) {
const patches = [];
// 节点不存在
if (!newVNode) {
patches.push({ type: 'REMOVE' });
return patches;
}
// 类型不同,替换节点
if (typeof oldVNode !== typeof newVNode ||
(typeof oldVNode === 'string' && oldVNode !== newVNode) ||
oldVNode.tag !== newVNode.tag) {
patches.push({ type: 'REPLACE', node: newVNode });
return patches;
}
// 比较属性
if (newVNode.props) {
const propsPatches = diffProps(oldVNode.props || {}, newVNode.props);
if (Object.keys(propsPatches).length) {
patches.push({ type: 'PROPS', props: propsPatches });
}
}
// 比较子节点
diffChildren(oldVNode.children || [], newVNode.children || [], patches);
return patches;
}
function diffProps(oldProps, newProps) {
const patches = {};
// 新增或修改的属性
for (const key in newProps) {
if (newProps[key] !== oldProps[key]) {
patches[key] = newProps[key];
}
}
// 删除的属性
for (const key in oldProps) {
if (!(key in newProps)) {
patches[key] = undefined;
}
}
return patches;
}
function diffChildren(oldChildren, newChildren, patches) {
const len = Math.max(oldChildren.length, newChildren.length);
for (let i = 0; i < len; i++) {
const childPatches = diff(oldChildren[i], newChildren[i]);
if (childPatches.length) {
patches.push({ type: 'CHILDREN', index: i, patches: childPatches });
}
}
}
```
---
## 2. Vue 响应式原理
> **场景**Vue 项目开发、理解数据驱动视图更新、排查响应式失效问题。
> **解决**:手动操作 DOM 繁琐易错,自动追踪数据变化并更新视图。
### Vue 2 (Object.defineProperty)
```js
function observe(obj) {
if (typeof obj !== 'object' || obj === null) return;
Object.keys(obj).forEach(key => {
let value = obj[key];
const dep = new Set();
observe(value); // 递归处理嵌套对象
Object.defineProperty(obj, key, {
get() {
if (currentEffect) dep.add(currentEffect);
return value;
},
set(newVal) {
if (newVal === value) return;
value = newVal;
observe(newVal);
dep.forEach(fn => fn());
}
});
});
}
let currentEffect = null;
function watchEffect(fn) {
currentEffect = fn;
fn();
currentEffect = null;
}
```
### Vue 3 (Proxy)
```js
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
track(target, key);
const result = Reflect.get(target, key, receiver);
return typeof result === 'object' ? reactive(result) : result;
},
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
trigger(target, key);
return result;
}
});
}
const targetMap = new WeakMap();
let activeEffect = null;
function track(target, key) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) targetMap.set(target, (depsMap = new Map()));
let dep = depsMap.get(key);
if (!dep) depsMap.set(key, (dep = new Set()));
dep.add(activeEffect);
}
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
depsMap.get(key)?.forEach(effect => effect());
}
function effect(fn) {
activeEffect = fn;
fn();
activeEffect = null;
}
```
---
## 3. React useState 简单模拟
> **场景**React 函数组件状态管理、理解 Hooks 为何不能在条件语句中调用。
> **解决**:函数组件无状态,通过闭包和数组模拟类组件的状态能力。
```js
let state = [];
let stateIndex = 0;
function useState(initialValue) {
const currentIndex = stateIndex;
state[currentIndex] = state[currentIndex] ?? initialValue;
const setState = (newValue) => {
state[currentIndex] = typeof newValue === 'function'
? newValue(state[currentIndex])
: newValue;
render(); // 触发重新渲染
};
stateIndex++;
return [state[currentIndex], setState];
}
function render() {
stateIndex = 0; // 重置索引
// 调用组件函数...
}
```
---
## 4. useEffect 简单模拟
> **场景**React 副作用处理(数据请求、事件订阅、定时器)、理解依赖数组作用。
> **解决**:函数组件中处理生命周期和副作用,替代类组件的 componentDidMount 等。
```js
let effectIndex = 0;
let effects = [];
function useEffect(callback, deps) {
const currentIndex = effectIndex;
const prevDeps = effects[currentIndex]?.deps;
const hasChanged = !prevDeps ||
deps.some((dep, i) => !Object.is(dep, prevDeps[i]));
if (hasChanged) {
// 执行清理函数
effects[currentIndex]?.cleanup?.();
// 延迟执行 effect
Promise.resolve().then(() => {
const cleanup = callback();
effects[currentIndex] = { deps, cleanup };
});
}
effectIndex++;
}
```
---
## 5. 简易 Redux
> **场景**:跨组件状态管理、理解单向数据流架构、实现时间旅行调试。
> **解决**:多组件共享状态混乱,集中管理应用状态并可预测地变更。
```js
function createStore(reducer) {
let state;
const listeners = [];
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
const subscribe = (listener) => {
listeners.push(listener);
return () => {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
};
dispatch({ type: '@@INIT' }); // 初始化 state
return { getState, dispatch, subscribe };
}
// 使用示例
const reducer = (state = { count: 0 }, action) => {
switch (action.type) {
case 'INCREMENT': return { count: state.count + 1 };
case 'DECREMENT': return { count: state.count - 1 };
default: return state;
}
};
```