前端常见手写代码题集
1. 手写Object.create
思路:将传入的对象作为原型
function create(obj) {
function F() { }
F.prototype = obj
return new F()
}
2. 手写 instanceof
思路:不断地从左边的原型链上去找
function MyInstanceof(left, right) {
let l = Object.getPrototypeOf(left);
let r = right.prototype;
while (1) {
if (!l) return false;
if (l === r) return true;
l = Object.getPrototypeOf(l)
}
}
3. 手写 new 操作符
思路:
- 创建一个空对象
- 设置原型对象
- this指向这个对象
function myNew(fn) {
let obj = {};
obj.__proto__ = fn.prototype;
let res = fn.call(obj);
return typeof res === 'object' ? res : obj
}
4. 手写 Promise.all
直接写
function MyPromiseAll(promises) {
return new Promise((resolve, reject) => {
let count = 0;
let res = [];
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then((value) => {
count++;
res[index] = value;
if (count === promises.length) {
return resolve(res)
}
})
.catch((err) => reject(err))
})
})
}
5. 手写 Promise.race
思路:返回第一个有结果的promise
function MyPromiseRace(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject)
}
})
}
6. 手写 Promise.allsettled
function allsettled(promises) {
return new Promise((resolve, reject) => {
const res = [];
let count = 0;
for (let i = 0; i < promises.length; i++) {
promises[i]
.then((value) => res[i] = { status: 'fulfilled', value })
.reject((reason) => res[i] = { status: 'rejected', reason })
.finally(() => {
count++;
if (count === promises.length) {
resolve(res)
}
})
}
})
}
7. 手写防抖、节流
// 防抖
function debounce(fn, wait) {
let timer = null;
return function (...args) {
const context = this;
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(() => {
fn.apply(context, args);
}, wait)
}
}
// 节流
function throttle(fn, wait) {
let timer = null;
return function (...args) {
const context = this;
if (timer) {
return
}
timer = setTimeout(() => {
fn.apply(context, args);
timer = null;
}, wait)
}
}
附加节流和防抖的应用场景:
- 节流:
- 监听滚动事件
- 调整窗口大小页面跟着变
- 输入框实时搜索
- 防抖:
- 用户输入的触发事件
- 表单提交
- 延迟加载
8. 手写call、apply、bind
Function.prototype.myCall = function (context, ...args) {
context = context || window
args = args || []
const key = new Symbol()
context[key] = this
const res = context[key](...args)
delete context[key]
return res
}
Function.prototype.myApply = function (context, args) {
context = context || window
args = args || []
const key = new Symbol()
context[key] = this
const res = context[key](...args)
delete context[key]
return res
}
Function.prototype.myBind = function (context, ...args) {
let self = this
args = args || []
return function (...newargs) {
const key = Symbol()
context[key] = self
const res = context[key](...args, ...newargs)
delete context[key]
return res
}
}
9. 手写AJAX请求
const url = '/server';
let xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
if (this.status === 200) {
console.log(this.response);
} else {
console.log(this.statusText);
}
}
xhr.onerror = function () {
console.log(this.statusText);
}
xhr.responseType = 'json';
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(null);
10. 手写深、浅拷贝
10.1 浅拷贝
- Object.assign()
- 扩展运算符
10.2 深拷贝
- JSON.stringify()
- lodash库
- 手写深拷贝
function deepClone(obj, map = new WeakMap()) { if (obj === null || typeof obj !== 'object' || map.has(obj)) { return obj; } map.set(obj, true) let newObj = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = deepClone(obj[key]); } } return newObj; }
11. 一行实现sleep函数
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}