下次接好运~

以下是JavaScript面试中高频出现的"手撕代码"题目详解,涵盖核心原理、代码实现与面试应答要点,结合最新技术实践整理:


⚙️ 一、原型与继承

  1. 手撕instanceof
    原理 :沿原型链向上查找,判断构造函数的prototype是否在对象原型链上。
    代码实现

    javascript 复制代码
    function myInstanceof(obj, constructor) {
      let proto = obj.__proto__;
      while (proto) {
        if (proto === constructor.prototype) return true;
        proto = proto.__proto__;
      }
      return false;
    }
    console.log(myInstanceof([], Array)); // true

    关键点 :递归访问__proto__,边界条件为proto === null

  2. 手撕new操作符
    原理 :创建空对象 → 绑定原型 → 执行构造函数 → 返回对象。
    代码实现

    javascript 复制代码
    function myNew(constructor, ...args) {
      const obj = Object.create(constructor.prototype);
      const result = constructor.apply(obj, args);
      return result instanceof Object ? result : obj;
    }
    function Person(name) { this.name = name; }
    const p = myNew(Person, 'Tom');

🔧 二、函数与this

  1. 手撕call/apply/bind
    核心思路 :通过临时绑定函数到上下文对象执行。
    call实现

    javascript 复制代码
    Function.prototype.myCall = function(context, ...args) {
      context = context || window;
      const fn = Symbol();
      context[fn] = this;
      const res = context...args;
      delete context[fn];
      return res;
    }

    区别

    • apply:第二参数为数组args
    • bind:返回新函数,合并参数[...args, ...newArgs]
  2. 柯里化(Currying)
    题目 :实现add(1)(2)(3) = 6
    实现

    javascript 复制代码
    function curry(fn) {
      return function curried(...args) {
        if (args.length >= fn.length) return fn(...args);
        return (...more) => curried(...args, ...more);
      };
    }
    const add = curry((a, b, c) => a + b + c);

三、异步控制

  1. 防抖(Debounce)
    场景 :搜索框输入停止后触发请求。
    实现

    javascript 复制代码
    function debounce(fn, delay) {
      let timer;
      return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => fn(...args), delay);
      };
    }
  2. 节流(Throttle)
    场景 :滚动事件触发频率控制。
    实现

    javascript 复制代码
    function throttle(fn, interval) {
      let lastTime = 0;
      return (...args) => {
        const now = Date.now();
        if (now - lastTime >= interval) {
          fn(...args);
          lastTime = now;
        }
      };
    }
  3. 手撕Promise
    核心功能 :状态机(pending/fulfilled/rejected)+ 回调队列。
    简化版

    javascript 复制代码
    class MyPromise {
      constructor(executor) {
        this.state = 'pending';
        this.value = null;
        this.onFulfilledCallbacks = [];
        const resolve = (value) => {
          if (this.state === 'pending') {
            this.state = 'fulfilled';
            this.value = value;
            this.onFulfilledCallbacks.forEach(cb => cb());
          }
        };
        executor(resolve);
      }
      then(onFulfilled) {
        return new MyPromise(resolve => {
          const wrapper = () => resolve(onFulfilled(this.value));
          if (this.state === 'fulfilled') wrapper();
          else this.onFulfilledCallbacks.push(wrapper);
        });
      }
    }

📚 四、数组操作

  1. 数组扁平化
    递归实现

    javascript 复制代码
    function flatten(arr) {
      return arr.reduce((pre, cur) => 
        pre.concat(Array.isArray(cur) ? flatten(cur) : cur)
      , []);
    }
    console.log(flatten([1, [2, [3]]])); // [1,2,3]
  2. 数组去重
    最优解Set + 扩展运算符

    javascript 复制代码
    const unique = arr => [...new Set(arr)];
  3. 手撕Array.reduce
    核心:处理初始值 + 遍历累加

    javascript 复制代码
    Array.prototype.myReduce = function(callback, init) {
      let acc = init ?? this[0];
      for (let i = init ? 0 : 1; i < this.length; i++) {
        acc = callback(acc, this[i], i, this);
      }
      return acc;
    }

🧩 五、对象操作

深拷贝(Deep Clone)
处理循环引用WeakMap存储已拷贝对象

javascript 复制代码
function deepClone(obj, map = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (map.has(obj)) return map.get(obj);
  const clone = Array.isArray(obj) ? [] : {};
  map.set(obj, clone);
  for (const key in obj) {
    clone[key] = deepClone(obj[key], map);
  }
  return clone;
}

💡 面试应答技巧

  1. 解释思路优先:先说明设计原理(如防抖的"延迟执行"),再写代码。
  2. 边界条件处理 :主动提及null判断、参数校验(如reduce的初始值)。
  3. 性能优化 :如深拷贝用WeakMap避免内存泄漏。
  4. 对比原生API :说明手写版与原生差异(如Promise未实现微队列)。

⚠️ 手写题核心考察点:

  • 原型链理解 (如instanceof
  • 异步控制能力 (如Promise状态机)
  • 函数式编程(如柯里化)
  • 内存管理意识(如深拷贝的循环引用处理)

掌握以上题目后,可覆盖90%前端面试手撕代码环节。建议实际编码测试边界用例(如数组方法处理稀疏数组)。

相关推荐
郝学胜-神的一滴5 分钟前
Spring Boot Actuator 保姆级教程
java·开发语言·spring boot·后端·程序人生
赵英英俊13 分钟前
Python day31
开发语言·python
剪刀石头布啊21 分钟前
var、let、const与闭包、垃圾回收
前端·javascript
剪刀石头布啊22 分钟前
js常见的单例
前端·javascript
剪刀石头布啊29 分钟前
iframe通信、跨标签通信的常见方案
前端·javascript·html
阿星做前端44 分钟前
如何构建一个自己的 Node.js 模块解析器:node:module 钩子详解
前端·javascript·node.js
程序员-Queen1 小时前
RDQS_c和RDQS_t的作用及区别
c语言·开发语言
慕y2741 小时前
Java学习第九十三部分——RestTemplate
java·开发语言·学习
上单带刀不带妹1 小时前
JavaScript 中的宏任务与微任务
开发语言·前端·javascript·ecmascript·宏任务·微任务
旋风菠萝1 小时前
设计模式---单例
android·java·开发语言