Skip to content

JS 模拟实现 ​

模拟实现 new ​

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

模拟实现 call ​

js
Function.prototype.myCall = function (context, ...args) {
  // context 可能为 null/undefined,此时指向全局对象(浏览器中是 window)
  context = context ?? globalThis
  // 使用 Symbol 避免属性名冲突
  const key = Symbol()
  context[key] = this
  const result = context[key](...args)
  delete context[key]
  return result
}
Function.prototype.myCall = function (context, ...args) {
  // context 可能为 null/undefined,此时指向全局对象(浏览器中是 window)
  context = context ?? globalThis
  // 使用 Symbol 避免属性名冲突
  const key = Symbol()
  context[key] = this
  const result = context[key](...args)
  delete context[key]
  return result
}

模拟实现 apply ​

js
Function.prototype.myApply = function (context, args) {
  context = context ?? globalThis
  const key = Symbol()
  context[key] = this
  const result = context[key](...(args || []))
  delete context[key]
  return result
}
Function.prototype.myApply = function (context, args) {
  context = context ?? globalThis
  const key = Symbol()
  context[key] = this
  const result = context[key](...(args || []))
  delete context[key]
  return result
}

模拟实现 bind ​

js
Function.prototype.myBind = function (context, ...bindArgs) {
  const fn = this
  return function (...callArgs) {
    return fn.apply(context, bindArgs.concat(callArgs))
  }
}

// 支持 new 操作的 bind(更完整版)
Function.prototype.myBind2 = function (context, ...bindArgs) {
  const fn = this
  function bound(...callArgs) {
    return fn.apply(this instanceof bound ? this : context, bindArgs.concat(callArgs))
  }
  bound.prototype = Object.create(fn.prototype)
  return bound
}
Function.prototype.myBind = function (context, ...bindArgs) {
  const fn = this
  return function (...callArgs) {
    return fn.apply(context, bindArgs.concat(callArgs))
  }
}

// 支持 new 操作的 bind(更完整版)
Function.prototype.myBind2 = function (context, ...bindArgs) {
  const fn = this
  function bound(...callArgs) {
    return fn.apply(this instanceof bound ? this : context, bindArgs.concat(callArgs))
  }
  bound.prototype = Object.create(fn.prototype)
  return bound
}

模拟实现 instanceof ​

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

模拟实现 Object.create ​

js
function myObjectCreate(proto) {
  function F() {}
  F.prototype = proto
  return new F()
}
function myObjectCreate(proto) {
  function F() {}
  F.prototype = proto
  return new F()
}

深拷贝 ​

js
// 基础版(不考虑循环引用、特殊对象)
function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) return obj
  const result = Array.isArray(obj) ? [] : {}
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      result[key] = deepClone(obj[key])
    }
  }
  return result
}

// 完整版(支持循环引用、Map、Set、Date、RegExp 等)
function deepCloneComplete(obj, map = new WeakMap()) {
  if (typeof obj !== 'object' || obj === null) return obj

  if (map.has(obj)) return map.get(obj)

  let result
  if (obj instanceof Date) result = new Date(obj)
  else if (obj instanceof RegExp) result = new RegExp(obj)
  else if (obj instanceof Map) {
    result = new Map()
    map.set(obj, result)
    obj.forEach((val, key) => result.set(key, deepCloneComplete(val, map)))
    return result
  } else if (obj instanceof Set) {
    result = new Set()
    map.set(obj, result)
    obj.forEach(val => result.add(deepCloneComplete(val, map)))
    return result
  } else {
    result = Array.isArray(obj) ? [] : {}
    map.set(obj, result)
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        result[key] = deepCloneComplete(obj[key], map)
      }
    }
  }
  return result
}
// 基础版(不考虑循环引用、特殊对象)
function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) return obj
  const result = Array.isArray(obj) ? [] : {}
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      result[key] = deepClone(obj[key])
    }
  }
  return result
}

// 完整版(支持循环引用、Map、Set、Date、RegExp 等)
function deepCloneComplete(obj, map = new WeakMap()) {
  if (typeof obj !== 'object' || obj === null) return obj

  if (map.has(obj)) return map.get(obj)

  let result
  if (obj instanceof Date) result = new Date(obj)
  else if (obj instanceof RegExp) result = new RegExp(obj)
  else if (obj instanceof Map) {
    result = new Map()
    map.set(obj, result)
    obj.forEach((val, key) => result.set(key, deepCloneComplete(val, map)))
    return result
  } else if (obj instanceof Set) {
    result = new Set()
    map.set(obj, result)
    obj.forEach(val => result.add(deepCloneComplete(val, map)))
    return result
  } else {
    result = Array.isArray(obj) ? [] : {}
    map.set(obj, result)
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        result[key] = deepCloneComplete(obj[key], map)
      }
    }
  }
  return result
}

模拟实现 Promise ​

js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  #state = PENDING
  #value = undefined
  #reason = undefined
  #onFulfilledCallbacks = []
  #onRejectedCallbacks = []

  constructor(executor) {
    const resolve = (value) => {
      if (this.#state !== PENDING) return
      this.#state = FULFILLED
      this.#value = value
      this.#onFulfilledCallbacks.forEach(fn => fn())
    }
    const reject = (reason) => {
      if (this.#state !== PENDING) return
      this.#state = REJECTED
      this.#reason = reason
      this.#onRejectedCallbacks.forEach(fn => fn())
    }
    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
    onRejected = typeof onRejected === 'function' ? onRejected : e => { throw e }

    const promise2 = new MyPromise((resolve, reject) => {
      if (this.#state === FULFILLED) {
        queueMicrotask(() => {
          try {
            const x = onFulfilled(this.#value)
            this.#resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      } else if (this.#state === REJECTED) {
        queueMicrotask(() => {
          try {
            const x = onRejected(this.#reason)
            this.#resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      } else {
        this.#onFulfilledCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              const x = onFulfilled(this.#value)
              this.#resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
        this.#onRejectedCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              const x = onRejected(this.#reason)
              this.#resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
      }
    })
    return promise2
  }

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

  catch(onRejected) {
    return this.then(null, onRejected)
  }

  static resolve(value) {
    return value instanceof MyPromise
      ? value
      : new MyPromise(resolve => resolve(value))
  }

  static reject(reason) {
    return new MyPromise((_, reject) => reject(reason))
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const results = []
      let count = 0
      if (promises.length === 0) resolve(results)
      promises.forEach((p, i) => {
        MyPromise.resolve(p).then(val => {
          results[i] = val
          count++
          if (count === promises.length) resolve(results)
        }, reject)
      })
    })
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach(p => MyPromise.resolve(p).then(resolve, reject))
    })
  }

  static allSettled(promises) {
    return new MyPromise(resolve => {
      const results = []
      let count = 0
      if (promises.length === 0) resolve(results)
      promises.forEach((p, i) => {
        MyPromise.resolve(p).then(
          value => { results[i] = { status: 'fulfilled', value }; count++; if (count === promises.length) resolve(results) },
          reason => { results[i] = { status: 'rejected', reason }; count++; if (count === promises.length) resolve(results) }
        )
      })
    })
  }
}
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  #state = PENDING
  #value = undefined
  #reason = undefined
  #onFulfilledCallbacks = []
  #onRejectedCallbacks = []

  constructor(executor) {
    const resolve = (value) => {
      if (this.#state !== PENDING) return
      this.#state = FULFILLED
      this.#value = value
      this.#onFulfilledCallbacks.forEach(fn => fn())
    }
    const reject = (reason) => {
      if (this.#state !== PENDING) return
      this.#state = REJECTED
      this.#reason = reason
      this.#onRejectedCallbacks.forEach(fn => fn())
    }
    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
    onRejected = typeof onRejected === 'function' ? onRejected : e => { throw e }

    const promise2 = new MyPromise((resolve, reject) => {
      if (this.#state === FULFILLED) {
        queueMicrotask(() => {
          try {
            const x = onFulfilled(this.#value)
            this.#resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      } else if (this.#state === REJECTED) {
        queueMicrotask(() => {
          try {
            const x = onRejected(this.#reason)
            this.#resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      } else {
        this.#onFulfilledCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              const x = onFulfilled(this.#value)
              this.#resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
        this.#onRejectedCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              const x = onRejected(this.#reason)
              this.#resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
      }
    })
    return promise2
  }

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

  catch(onRejected) {
    return this.then(null, onRejected)
  }

  static resolve(value) {
    return value instanceof MyPromise
      ? value
      : new MyPromise(resolve => resolve(value))
  }

  static reject(reason) {
    return new MyPromise((_, reject) => reject(reason))
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const results = []
      let count = 0
      if (promises.length === 0) resolve(results)
      promises.forEach((p, i) => {
        MyPromise.resolve(p).then(val => {
          results[i] = val
          count++
          if (count === promises.length) resolve(results)
        }, reject)
      })
    })
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach(p => MyPromise.resolve(p).then(resolve, reject))
    })
  }

  static allSettled(promises) {
    return new MyPromise(resolve => {
      const results = []
      let count = 0
      if (promises.length === 0) resolve(results)
      promises.forEach((p, i) => {
        MyPromise.resolve(p).then(
          value => { results[i] = { status: 'fulfilled', value }; count++; if (count === promises.length) resolve(results) },
          reason => { results[i] = { status: 'rejected', reason }; count++; if (count === promises.length) resolve(results) }
        )
      })
    })
  }
}

模拟实现 Array.prototype.map ​

js
Array.prototype.myMap = function (fn, thisArg) {
  const result = []
  for (let i = 0; i < this.length; i++) {
    if (i in this) {
      result[i] = fn.call(thisArg, this[i], i, this)
    }
  }
  return result
}
Array.prototype.myMap = function (fn, thisArg) {
  const result = []
  for (let i = 0; i < this.length; i++) {
    if (i in this) {
      result[i] = fn.call(thisArg, this[i], i, this)
    }
  }
  return result
}

模拟实现 Array.prototype.filter ​

js
Array.prototype.myFilter = function (fn, thisArg) {
  const result = []
  for (let i = 0; i < this.length; i++) {
    if (i in this) {
      if (fn.call(thisArg, this[i], i, this)) {
        result.push(this[i])
      }
    }
  }
  return result
}
Array.prototype.myFilter = function (fn, thisArg) {
  const result = []
  for (let i = 0; i < this.length; i++) {
    if (i in this) {
      if (fn.call(thisArg, this[i], i, this)) {
        result.push(this[i])
      }
    }
  }
  return result
}

模拟实现 Array.prototype.reduce ​

js
Array.prototype.myReduce = function (fn, initialValue) {
  let acc = initialValue
  let startIndex = 0
  if (acc === undefined) {
    // 找第一个非空元素
    for (let i = 0; i < this.length; i++) {
      if (i in this) {
        acc = this[i]
        startIndex = i + 1
        break
      }
    }
    if (acc === undefined) throw new TypeError('Reduce of empty array with no initial value')
  }
  for (let i = startIndex; i < this.length; i++) {
    if (i in this) {
      acc = fn(acc, this[i], i, this)
    }
  }
  return acc
}
Array.prototype.myReduce = function (fn, initialValue) {
  let acc = initialValue
  let startIndex = 0
  if (acc === undefined) {
    // 找第一个非空元素
    for (let i = 0; i < this.length; i++) {
      if (i in this) {
        acc = this[i]
        startIndex = i + 1
        break
      }
    }
    if (acc === undefined) throw new TypeError('Reduce of empty array with no initial value')
  }
  for (let i = startIndex; i < this.length; i++) {
    if (i in this) {
      acc = fn(acc, this[i], i, this)
    }
  }
  return acc
}

防抖(debounce) ​

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

// 立即执行版
function debounceImmediate(fn, delay = 300) {
  let timer = null
  let immediate = true
  return function (...args) {
    clearTimeout(timer)
    if (immediate) {
      fn.apply(this, args)
      immediate = false
    }
    timer = setTimeout(() => { immediate = true }, delay)
  }
}
function debounce(fn, delay = 300) {
  let timer = null
  return function (...args) {
    clearTimeout(timer)
    timer = setTimeout(() => fn.apply(this, args), delay)
  }
}

// 立即执行版
function debounceImmediate(fn, delay = 300) {
  let timer = null
  let immediate = true
  return function (...args) {
    clearTimeout(timer)
    if (immediate) {
      fn.apply(this, args)
      immediate = false
    }
    timer = setTimeout(() => { immediate = true }, delay)
  }
}

节流(throttle) ​

js
// 时间戳版(立即执行)
function throttle(fn, interval = 300) {
  let last = 0
  return function (...args) {
    const now = Date.now()
    if (now - last >= interval) {
      last = now
      fn.apply(this, args)
    }
  }
}

// 定时器版(延迟执行)
function throttleTimer(fn, interval = 300) {
  let timer = null
  return function (...args) {
    if (!timer) {
      timer = setTimeout(() => {
        timer = null
        fn.apply(this, args)
      }, interval)
    }
  }
}
// 时间戳版(立即执行)
function throttle(fn, interval = 300) {
  let last = 0
  return function (...args) {
    const now = Date.now()
    if (now - last >= interval) {
      last = now
      fn.apply(this, args)
    }
  }
}

// 定时器版(延迟执行)
function throttleTimer(fn, interval = 300) {
  let timer = null
  return function (...args) {
    if (!timer) {
      timer = setTimeout(() => {
        timer = null
        fn.apply(this, args)
      }, interval)
    }
  }
}

模拟实现 JSON.stringify ​

js
function myJSONStringify(data) {
  if (data === null) return 'null'
  if (typeof data === 'string') return `"${data}"`
  if (typeof data === 'number' || typeof data === 'boolean') return String(data)
  if (typeof data === 'undefined' || typeof data === 'function' || typeof data === 'symbol') return undefined

  if (Array.isArray(data)) {
    const arr = data.map(item => myJSONStringify(item) ?? 'null')
    return `[${arr.join(',')}]`
  }

  if (typeof data === 'object') {
    const keys = Object.keys(data)
    const pairs = keys.filter(k => myJSONStringify(data[k]) !== undefined)
      .map(k => `"${k}":${myJSONStringify(data[k])}`)
    return `{${pairs.join(',')}}`
  }
}
function myJSONStringify(data) {
  if (data === null) return 'null'
  if (typeof data === 'string') return `"${data}"`
  if (typeof data === 'number' || typeof data === 'boolean') return String(data)
  if (typeof data === 'undefined' || typeof data === 'function' || typeof data === 'symbol') return undefined

  if (Array.isArray(data)) {
    const arr = data.map(item => myJSONStringify(item) ?? 'null')
    return `[${arr.join(',')}]`
  }

  if (typeof data === 'object') {
    const keys = Object.keys(data)
    const pairs = keys.filter(k => myJSONStringify(data[k]) !== undefined)
      .map(k => `"${k}":${myJSONStringify(data[k])}`)
    return `{${pairs.join(',')}}`
  }
}

模拟实现 compose(函数组合) ​

js
function compose(...fns) {
  if (fns.length === 0) return arg => arg
  if (fns.length === 1) return fns[0]
  return fns.reduce((a, b) => (...args) => a(b(...args)))
}

// 使用:compose(fn3, fn2, fn1)(x) => fn3(fn2(fn1(x)))
function compose(...fns) {
  if (fns.length === 0) return arg => arg
  if (fns.length === 1) return fns[0]
  return fns.reduce((a, b) => (...args) => a(b(...args)))
}

// 使用:compose(fn3, fn2, fn1)(x) => fn3(fn2(fn1(x)))