Skip to content

高级 JavaScript 面试题

执行上下文与作用域

1. 执行上下文类型

  • 全局执行上下文:默认上下文,创建全局对象(浏览器中是 window)
  • 函数执行上下文:每次函数调用创建一个新的执行上下文
  • Eval 执行上下文:eval 函数内部的上下文

2. 作用域链

当查找变量时,会沿着作用域链向上查找:

当前作用域 → 外层函数作用域 → ... → 全局作用域

3. 闭包

闭包是指有权访问另一个函数作用域中变量的函数。

应用场景

  • 数据私有化
  • 函数柯里化
  • 节流防抖
  • 缓存计算结果

原型与继承

1. 原型链

对象.__proto__ → 构造函数.prototype → Object.prototype → null

2. 继承方式

方式优点缺点
原型链继承简单引用类型共享
构造函数继承不共享引用不能继承原型方法
组合继承综合优点调用两次父类构造函数
寄生组合继承最优方案稍复杂
ES6 class extends语法简洁本质是语法糖

3. 手写 new 操作符

js
function myNew(fn, ...args) {
  const obj = Object.create(fn.prototype)
  const result = fn.apply(obj, args)
  return result instanceof Object ? result : obj
}

异步编程

1. Promise 原理

Promise 是异步编程的一种解决方案,代表一个异步操作的最终完成或失败。

状态

  • pending(等待)
  • fulfilled(成功)
  • rejected(失败)

手写 Promise

js
class MyPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = undefined
    this.reason = undefined
    this.onFulfilledCallbacks = []
    this.onRejectedCallbacks = []

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
        this.onFulfilledCallbacks.forEach((fn) => fn())
      }
    }

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallbacks.forEach((fn) => fn())
      }
    }

    try {
      executor(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }

  then(onFulfilled, onRejected) {
    // 实现链式调用...
  }
}

2. async/await 原理

async/await 是 Promise 的语法糖:

  • async 函数返回一个 Promise
  • await 会暂停 async 函数的执行,等待 Promise 完成

3. 宏任务与微任务

宏任务 (macrotask)

  • setTimeout / setInterval
  • setImmediate(Node.js)
  • I/O 操作
  • UI 渲染

微任务 (microtask)

  • Promise.then / catch / finally
  • process.nextTick(Node.js,优先级最高)
  • MutationObserver

执行顺序:同步代码 → 所有微任务 → 一个宏任务 → 所有微任务 → 一个宏任务...

手写代码题

1. 防抖 (Debounce)

js
function debounce(fn, delay, immediate = false) {
  let timer = null
  return function (...args) {
    if (timer) clearTimeout(timer)
    if (immediate && !timer) {
      fn.apply(this, args)
    }
    timer = setTimeout(() => {
      if (!immediate) {
        fn.apply(this, args)
      }
      timer = null
    }, delay)
  }
}

2. 节流 (Throttle)

js
function throttle(fn, delay) {
  let lastTime = 0
  return function (...args) {
    const now = Date.now()
    if (now - lastTime >= delay) {
      fn.apply(this, args)
      lastTime = now
    }
  }
}

3. 深拷贝

js
function deepClone(obj, hash = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') return obj
  if (obj instanceof Date) return new Date(obj)
  if (obj instanceof RegExp) return new RegExp(obj)
  if (hash.has(obj)) return hash.get(obj)

  const cloneObj = new obj.constructor()
  hash.set(obj, cloneObj)

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloneObj[key] = deepClone(obj[key], hash)
    }
  }
  return cloneObj
}

4. Promise.all

js
function promiseAll(promises) {
  return new Promise((resolve, reject) => {
    const results = []
    let completed = 0

    promises.forEach((promise, index) => {
      Promise.resolve(promise)
        .then((value) => {
          results[index] = value
          completed++
          if (completed === promises.length) {
            resolve(results)
          }
        })
        .catch(reject)
    })
  })
}

5. 数组扁平化

js
function flatten(arr, depth = Infinity) {
  return depth > 0
    ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatten(val, depth - 1) : val), [])
    : arr.slice()
}

内存管理

1. 垃圾回收机制

标记清除(Mark-Sweep)

  1. 标记阶段:遍历所有对象,标记可达对象
  2. 清除阶段:清除未标记的对象

引用计数

  • 跟踪每个值的引用次数
  • 引用次数为 0 时回收
  • 缺点:无法处理循环引用

2. 内存泄漏场景

  • 未清理的定时器和事件监听
  • 全局变量
  • 闭包引用
  • DOM 引用未释放
  • console.log 缓存

设计模式

常用设计模式

模式应用场景
单例模式全局唯一实例(如 Vuex store)
工厂模式创建复杂对象
观察者模式事件监听、发布订阅
策略模式表单验证、不同算法切换
代理模式Vue 响应式、图片懒加载
装饰器模式扩展功能、AOP

观察者模式 vs 发布订阅模式

  • 观察者模式:Subject 直接通知 Observer,耦合度较高
  • 发布订阅模式:通过 EventBus 中间件通信,完全解耦