高频前端面试考点之手写题(一)

66 阅读2分钟

1. 手写 Object.create

Object.create 方法创建一个新对象,使用现有的对象来提供新创建的对象的 __proto__

function create(obj) {
  function F() {}
  F.prototype = obj
  return new F()
}

核心原理:通过一个中间构造函数,将其原型指向传入的对象,然后返回这个构造函数的实例。

2. 手写 instanceof 方法

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

function myInstanceof(left, right) {
  let proto = Object.getPrototypeOf(left)
  let prototype = right.prototype
  
  while (true) {
    if (!proto) return false
    if (proto === prototype) return true
    proto = Object.getPrototypeOf(proto)
  }
}

实现要点:沿着原型链向上查找,直到找到匹配的原型或到达链的末端。

3. 手写 new 操作符

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。

function myNew(constructor, ...args) {
  // 1. 创建一个新对象,并将其原型指向构造函数的prototype
  const obj = Object.create(constructor.prototype)
  
  // 2. 执行构造函数,绑定this到新对象
  const result = constructor.apply(obj, args)
  
  // 3. 如果构造函数返回了一个对象,则返回该对象
  return result instanceof Object ? result : obj
}

关键步骤:原型连接、构造函数执行、返回值处理。

4. 手写 Promise

Promise 是异步编程的一种解决方案,比传统的回调函数更加合理和强大。

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) {
    // then方法实现见下一节
  }
}

5. 手写 Promise.then

then 方法返回一个 Promise,它最多需要有两个参数:Promise 的成功和失败情况的回调函数。

then(onFulfilled, onRejected) {
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
  onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
  
  const promise2 = new MyPromise((resolve, reject) => {
    if (this.state === 'fulfilled') {
      setTimeout(() => {
        try {
          const x = onFulfilled(this.value)
          resolvePromise(promise2, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      })
    } else if (this.state === 'rejected') {
      setTimeout(() => {
        try {
          const x = onRejected(this.reason)
          resolvePromise(promise2, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      })
    } else if (this.state === 'pending') {
      this.onFulfilledCallbacks.push(() => {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      })
      
      this.onRejectedCallbacks.push(() => {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      })
    }
  })
  
  return promise2
}

function resolvePromise(promise2, x, resolve, reject) {
  if (x === promise2) {
    return reject(new TypeError('Chaining cycle detected for promise'))
  }
  
  if (x instanceof MyPromise) {
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}

6. 手写 Promise.all

Promise.all 方法接收一个promise的iterable类型输入,并返回一个Promise实例。

function promiseAll(promises) {
  return new Promise((resolve, reject) => {
    let results = []
    let count = 0
    
    promises.forEach((promise, index) => {
      Promise.resolve(promise).then(res => {
        results[index] = res
        count++
        
        if (count === promises.length) {
          resolve(results)
        }
      }).catch(reject)
    })
  })
}

特点:全部成功时返回结果数组,有一个失败立即拒绝。

7. 手写 Promise.race

Promise.race 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。

function promiseRace(promises) {
  return new Promise((resolve, reject) => {
    promises.forEach(promise => {
      Promise.resolve(promise).then(resolve).catch(reject)
    })
  })
}

特点:竞速,第一个 settled 的 promise 决定结果。

8. 手写防抖函数

防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

function debounce(fn, delay) {
  let timer = null
  
  return function (...args) {
    clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(this, args)
    }, delay)
  }
}

应用场景:搜索框输入、窗口大小调整。