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)))
Cao Note