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

5.1 KiB

框架相关算法

1. 虚拟DOM Diff 算法

简化版 Diff 实现

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 2 (Object.defineProperty)

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)

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 简单模拟

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 简单模拟

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

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;
  }
};