前端八股之手写代码
Web
2025-03-13 - 16:321065
手写代码题
1. Object.create
function create(obj) {
function F() {}
F.prototype = obj
return new F()
}
2. instanceof
function myInstanceof(left, right) {
let proto = Object.getPrototypeOf(left)
const prototype = right.prototype
while (true) {
if (!proto) {
return false
}
if(proto === prototype) {
return true
}
proto = Object.getPrototypeOf(proto)
}
}
3. new
操作符
function myNew(func, ...args) {
const obj = Object.create(Object.getPrototypeOf(func))
const result = func.apply(obj, args)
return result instanceof Object ? result : obj
}
4. Promise
const pending = 'pending'
const resolved = 'resolved'
const rejected = 'rejected'
class Promise {
constructor(fn) {
this.state = pending
this.value = null
this.resolvedCallbacks = []
this.rejectedCallbacks = []
try {
fn(this.resolve.bind(this), this.reject.bind(this))
} catch {
this.reject(e)
}
}
resolve(value) {
if (value instanceof Promise) {
return value.then(this.resolve, this.reject)
}
// 保证代码执行顺序在本轮事件循环末尾
setTimeout(() => {
if (this.state === pending) {
this.state = resolved
this.value = value
this.resolvedCallbacks.forEach(cb => cb(value))
}
}, 0)
}
reject(value) {
setTimeout(() => {
if (this.state === pending) {
this.state = rejected
this.value = value
this.rejectedCallbacks.forEach(cb => cb(value))
}
}, 0)
}
then(onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value => value
onRejected = typeof onRejected === 'function' ? onRejected : err => throw err
return new Promise((resolve, reject) => {
if (this.state === pending) {
this.resolvedCallbacks.push(onResolved)
this.rejectedCallbacks.push(onRejected)
} else if (this.state === resolved) {
try {
const result = onResolved(this.value)
if (result instanceof Promise) {
result.then(v => resolve(v), e => reject(e))
}
} catch (e) {
reject(e)
}
} else if (this.state === rejected) {
onRejected(this.value)
}
})
}
}
5. Promise.all
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises) || !promises.every(promise => promise instanceof Promise)) {
reject(new TypeError('Invalid Arguments'))
}
const result = []
let completeCount = 0
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(value => {
result[index] = value
completeCount++
if (completeCount === promises.length) {
resolve(result)
}
})
.catch(err => {
reject(err)
})
})
})
}
6. Promise.race
Promise.race = function (promises) {
if (!Array.isArray(promises) || !promises.every(promise => promise instanceof Promise)) {
return Promise.reject(new TypeError('Invalid Arguments'))
}
return new Promise((resolve, reject) => {
promises.forEach(promise => {
Promise.resolve(promise).then(resolve).catch(reject)
})
})
}
7. 防抖函数
function debounce(fn, delay) {
let timer = null
return function (...args) {
const context = this
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(context, args)
}, delay)
}
}
8. 节流函数
function throttle(fn, delay) {
let timer = null
let startTime = Date.now()
return function (...args) {
const context = this
const curTime = Date.now()
const remaining = delay - (curTime - startTime)
clearTimeout(timer)
if (remaining <= 0) {
fn.apply(context, args)
startTime = Date.now()
} else {
timer = setTimeout(() => {
fn.apply(context, args)
}, remaining)
}
}
}
9. Function.prototype.call
Function.prototype.call = function(context, ...args) {
context = context ?? window
context.fun = this
const result = context.fun(...args)
delete context.fun
return result
}
10. Function.prototype.apply
Function.prototype.apply = function(context, args) {
context = context ?? window
context.fun = this
const result = context.fun(...args)
delete context.fun
return result
}
11. Function.prototype.bind
Function.prototype.bind = function(context, ...args) {
const context = this
return function(...rest) {
return context.call(context, ...args, ...rest)
}
}
12. 函数柯里化
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.call(this, ...args)
}
return function(...moreArgs) {
return curried.call(this, ...args, ...moreArgs)
}
}
}
13. 浅拷贝
function clone(obj) {
if (object == null || typeof obj !== 'object') {
return obj
}
if (Array.isArray(obj)) {
const copy = []
for (const item of obj) {
copy.push(item)
}
return copy
}
const copy = {}
for (const key of Object.keys(obj)) {
copy[key] = obj[key]
}
return copy
}
14. 深拷贝
function deepClone(obj, map = new WeakMap()) {
if (obj == null || typeof obj !== 'object') {
return obj
}
if (map.has(obj)) {
return map.get(obj)
}
if (Array.isArray(obj)) {
const copy = []
map.set(obj, copy)
for (const item of obj) {
copy.push(deepClone(item, map))
}
return copy
}
if (obj instanceof Date) {
return new Date(obj.getTime())
}
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags)
}
const copy = Object.create(Object.getPrototypeOf(obj))
map.set(obj, copy)
for (const key of Object.keys(obj)) {
copy[key] = deepClone(obj[key], map)
}
return copy
}
当然还有ES2021新增的structuredClone()
,是原生的深拷贝
15. 数组的乱序输出
function shuffle(arr) {
for (let i = 0; i < arr.length; i++) {
const randomIndex = Math.round(Math.random() * (arr.length - 1 - i)) + i
[arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]]
}
}
16. 数组扁平化
function flatten(arr, depth = 1) {
if (depth === 0) {
return arr
}
return arr.reduce((acc, val) => {
acc.concat(Array.isArray(val) ? flatten(val, depth - 1) : val)
}, [])
}
还有一个取巧的办法就是toString()后再split()
17. 数组去重
不用Set
function unique(arr) {
const map = new Map()
const res = []
for (const item of arr) {
if (!map.has(item)) {
map.set(item, true)
res.push(item)
}
}
return res
}
ES6直接用[...new Set(arr)]
18. Array.Prototype.reduce
Array.prototype.reduce = function (fn, ...init) {
let next = init.length ? init[0] : this[0]
for (let i = init.length ? 0 : 1; i < this.length; i++) {
next = fn(next, this[i], i)
}
return next
}
场景题
1. 实现调度器
interface ITask {
priority: 1 | 2 | 3
action: () => Promise<any>
}
class Schedualer {
private readonly queue: ITask[] = []
private running: number = 0
add(task: ITask) {
let index = 0
while (index < this.queue.length && task.priority >= this.queue[index].priority) {
index++
}
this.queue.splice(index, 0, task)
Promise.resolve().then(() => this.tryRunNext())
}
private tryRunNext() {
while (this.running < 2 && this.queue.length > 0) {
const task = this.queue.shift()!
this.running++
task.action().finally(() => {
this.running--
this.tryRunNext()
})
}
}
}
算法题
1. 给数字添加千分符
正则表达式方法,没有考虑小数
function numberThousands(number, seperator = ',') {
// 这个正则捕获一个数字,其数字后面要求跟着3的倍数个数字(使用?=正向肯定预查)
// 然后再通过'$1'来引用第一个捕获组,在捕获组后面添加分隔符
return String(number).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + seperator)
}
如果考虑小数的话
function numberThousands(number, seperator = ',') {
const str = String(number)
const parts = str.split('.')
parts[0] = parts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + seperator)
return parts.length > 1 ? parts.join('.') : parts[0]
}
话题状态:正常
25