总结一下平时积累的 JS 中常见的一些手写实现
实现原生方法
实现 new
function myNew(constructor, ...args) {
// 创建一个空对象,并将其原型设置为构造函数的原型
const obj = Object.create(constructor.prototype);
// 调用构造函数,并将 this 指向新创建的对象
const result = constructor.apply(obj, args);
// 如果构造函数返回了一个对象,则返回该对象;否则返回新创建的对象
return typeof result === 'object' && result !== null ? result : obj;
}
实现 typeof
const typeof = (obj) => {
return prototype.toString.call(obj).slice(8, -1).toLowerCase();
};
实现 instanceOf
const instanceOf = (left, right) => {
if (typeof left !== 'object' || left === null) {
return false;
}
// 获取原型
let proto = Object.getPrototyprof(left);
let targetProto = right.prototype;
while(true) {
if (proto === null) {
return false;
}
if (proto === targetProto) {
return true;
}
proto = Object.getPrototyprof(proto);
};
实现 forEach
Array.prototype.forEach1 = function (fn, args) {
if(!this || !Array.isArray(this)) {
throw 'need an array';
}
if(!fn instanceof Function) {
throw 'need a function'
}
const arr = this.slice();
let i = 0;
while(i < arr.length) {
fn.call(this, args, arr[i], i++, arr);
}
}
实现 map
Array.prototype.map1 = function (fn, args) {
if(!this || !Array.isArray(this)) {
throw 'need an array';
}
if(!fn instanceof Function) {
throw 'need a function'
}
const arr = this.slice();
let i = 0;
let results = []
while(i < arr.length) {
results.push(fn.call(this, args, arr[i], i++, arr));
}
return results;
}
实现 filter
Array.prototype.filter1 = function (fn, args) {
if(!this || !Array.isArray(this)) {
throw 'need an array';
}
if(!fn instanceof Function) {
throw 'need a function'
}
const arr = this.slice();
let i = 0;
let results = []
while(i < arr.length) {
if(fn.call(this, args, arr[i], i, arr)) {
results.push(arr[i])
}
i++
}
return results;
}
实现 Object.assign
Object.assign1 = function (target, ...args) {
if (!target) {
throw 'need a object';
}
args.forEach((item) => {
if (item) {
for (let key in item) {
if (item.hasOwnProperty(key)) {
target[key] = item[key];
}
}
}
});
return target;
};
实现 Promise
const PENDING = 'pending';
const FULLFILLED = 'fullfiled';
const REJECTED = 'rejected';
class MyPromise {
constructor (executor) {
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
/** 状态 */
status = PENDING
/** 成功的值 */
value = null
/** 失败的原因 */
reason = null
/** 存储成功回调 */
onFulfilledCallbacks = [];
/** 存储失败回调 */
onRejectedCallbacks = [];
resolve = (value) => {
// 如果状态不是等待,阻止程序向下执行
if (this.status !== PENDING) {
return;
}
this.status = FULLFILLED;
this.value = value;
// 将所有成功的回调拿出来执行
while(this.onFulfilledCallbacks.length) {
this.onFulfilledCallbacks.shift()?.(value);
}
}
reject = (reason) => {
// 如果状态不是等待,阻止程序向下执行
if (this.status !== PENDING) {
return;
}
this.status = REJECTED;
this.reason = reason;
// 将所有失败的回调拿出来执行
while(this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()?.(reason);
}
}
then(onFulfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject) => {
// 成功回调
if(this.status === FULLFILLED) {
// 模拟异步
setTimeout(() => {
try {
const val = onFulfilled(this.value);
resolvePromise(promise2, val, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
const val = onRejected(this.reason);
resolvePromise(promise2, val, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else {
// 等待状态
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
});
return promise2;
}
}
function resolvePromise(promise, val, resolve, reject) {
if (promise === val) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
if (val instanceof MyPromise) {
val.then(resolve, reject);
} else {
resolve(val);
}
}
实现 Promise.all
只要有一个失败就失败
Promise.all1 = function(promises) {
if (!Array.isArray(promises)) {
throw 'need an array';
}
let index = 0;
let results = [];
return new Promise((resolve, reject) => {
promises.forEach((p, i) => {
Promise.resolve(p).then(
val => {
index++;
results[i] = val;
// 所有的都成功了
if(index === promises.length) {
resolve(results);
}
},
err => {
// 有一个失败就失败
reject(err);
}
);
});
});
}
实现 Promsie.race
只要有一个relove或reject,返回的promise就relove或reject
Promise.race1 = function(promises) {
if (!Array.isArray(promises)) {
throw 'need an array';
}
return new Promise((resolve, reject) => {
promises.forEach(p => {
Promise.resolve(p).then(
val => {
resolve(val);
},
err => {
reject(err);
}
);
});
});
}
实现 Promsie.any
只要有一个relove,返回的promise就relove
Promise.any1 = function(promises) {
if (!Array.isArray(promises)) {
throw 'need an array';
}
let errors = [];
return new Promise((resolve, reject) => {
promises.forEach(p => {
Promise.resolve(p).then(
val => {
resolve(val);
},
err => {
errors.push(err);
if (errors.length === promises.length) {
reject(errors);
}
}
);
});
});
}
实现 Promise.allSettled
只有全部完成才reslove
Promise.allSettled1 = function(promises) {
if (!Array.isArray(promises)) {
throw 'need an array';
}
let results = [];
return new Promise((resolve, reject) => {
promises.forEach((p, i) => {
Promise.resolve(p).then(
val => {
results.push({
status: 'fulfilled',
value: val,
});
if(results.length === promises.length) {
resolve(results);
}
},
err => {
results.push({
status: 'rejected',
value: val,
});
if(results.length === promises.length) {
resolve(results);
}
}
);
});
});
}
实现防抖
const debounce = (fn, time) => {
if (!fn instanceOf function) {
return false;
}
let timer = null;
return function(...args) {
timer && clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, time)
}
};
实现节流
// 使用时间戳
const throttle = (fn, time) => {
if (!fn instanceOf function) {
return false;
}
let lastTime = 0;
return function(...args) {
let now = Date.now();
if (now - lastTime > time) {
lastTime = now;
fn.apply(this, args);
}
}
};
// 使用定时器
const throttle = (fn, time) => {
if (!fn instanceof function) {
return false;
}
// 节流标识
let limited = false;
let start = Date.now();
let timer = null;
return function(...args) {
limited = limited && (Date.now() - start < time);
// 处在节流中
if (limited) {
timer && clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
limited = true;
start = Date.now();
}, time);
} else {
limited = true;
start = Date.now();
fn.apply(this, args);
}
}
};
扁平化
数组扁平化
const flat = (arr, dep) => {
if(dep <= 0 || !Array.isArray(arr)) {
return arr;
}
return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? flat(cur, dep- 1) : cur) , []);
};
const arr1 = [1, [2, 3], [4, 5, [6, 7]]];
const depth1 = 1;
console.log(flat(arr1, depth1)); // 输出: [1, 2, 3, 4, 5, [6, 7]]
对象扁平化
const objectFlat = (obj) => {
const res = {};
const process = (key, value) => {
if (typeof value !== 'object' || value == null) {
if (key) {
res[key] = value;
}
} else if (Array.isArray(value)) {
value.forEach((item, index) => {
process(`${key}[${index}]`, item);
});
if (value.length === 0) {
res[key] = [];
}
} else {
const keys = Object.keys(value);
keys.forEach(item => {
process(key ? `${key}.${item}` : `${item}`, value[item]);
});
if (keys.length && key) {
res[key] = {};
}
}
};
process('', obj);
return res;
};
const obj1 = { a: 1, b: { c: 2, d: { e: 3, f: { g: 4 } } } };
console.log(objectFlat(obj1)); // 输出: { "a": 1, "b.c": 2, "b.d.e": 3, "b.d.f.g": 4 }
柯里化
const curry = (fn) => {
const curryInner = (...args) => {
// 当参数长度一致时 (函数的length表示形参的个数)
if (args.length === fn.length) {
return fn(...args);
}
// 递归返回处理剩余参数
return (...args1) => curryInner(...args, ...args1);
};
return curryInner();
}
const add = curry((x, y, z) => x + y + z);
add(1)(2)(3) // 6
layzyMan
class lazyMan {
constructor(name) {
this.tasks = [];
this.name = name;
console.log(`Hi Im ${name}`);
setTimeout(() => {
this.next();
});
}
sleep(time) {
// 定时器实现 sleep
this.tasks.push(() => {
console.log('sleep');
setTimeout(() => {
this.next();
}, time);
});
// 实现链式的关键
return this;
}
eat(food) {
this.tasks.push(() => {
console.log(`eat ${food}`);
this.next();
});
return this;
}
next() {
const fn = this.tasks.shift();
fn && fn();
}
}
const lazyMan = new LazyMan('John');
// 输出: Hi im John
lazyMan.sleep(2000).eat('breakfast');
// 等待2秒后输出: sleep
// 然后输出: eat breakfast
lazyMan.eat('lunch').sleep(3000).eat('dinner');
// 输出: eat lunch
// 等待3秒后输出: sleep
// 然后输出: eat dinner
去重
普通数组去重
// 用 filter 实现
const uniqueArray0 = (arr) => {
return arr.filter((item, index) => arr.indexOf(item) === index);
}
// 用 reduce 实现
const uniqueArray1 = (arr) => {
return arr.reduce((pre, cur) => pre.includes(cur) ? pre : [...pre, cur], []);
};
// 双重循环
const uniqueArray2 = (arr) => {
const result = [];
for (let i = 0; i < arr.length; i++) {
let isDuplicate = false;
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
result.push(arr[i]);
}
}
return result;
};
// 键值对
const uniqueArray3 = (arr) => {
const obj = {};
for (let i = 0; i < arr.length; i++) {
obj[arr[i]] = true;
}
return Object.keys(obj)
};
对象数组去重
只要对象内的所有属性的值相同,就算相同元素。
const isEqual = (left, right) => {
if (left === right) {
return true;
}
if (typeof left !== typeof right) {
return false;
}
if (typeof left !== 'object' || left === null || right === null) {
return left === right;
}
const leftKeys = Object.keys(left);
const rightKeys = Object.keys(right);
if (leftKeys.length !== rightKeys.length) {
return false;
}
for (let key of leftKeys) {
if (!right.hasOwnProperty(key)) {
return false;
}
if (!isEqual(left[key], right[key])) {
return false;
}
}
return true;
};
const uniqueObject = (arr) => {
return arr.filter((item, index) => {
for (let i = 0; i < index; i++) {
if (isEqual(item, arr[i])) {
return false;
}
}
return true;
});
};
实现一个deepClone
const deepClone = (obj, map = new WeakMap()) => {
const toString = Object.prototype.toString;
// null, undefined, {}, function
if(!obj || typeof obj !== 'object') {
return obj;
}
// 日期格式
if(toString.call(obj) === '[object Date]') {
return new Date(obj.getTime());
}
// 正则表达式
if(toString.call(obj) === '[object RegExp]') {
var flags = [];
if(obj.global) {
flags.push('g');
}
if(obj.multiline) {
flags.push('m');
}
if(obj.ignoreCase) {
flags.push('i');
}
return new RegExp(obj.source, flags.join(''))
}
let cloneObj = obj instanceof Array ? [] : {}
// 防止循环引用
if (map.get(obj)) {
return obj;
}
map.set(obj, cloneObj);
for(let i in obj) {
if(obj.hasOwnProperty(i)) {
cloneObj[i] = deepClone(obj[i], map);
}
}
return cloneObj;
}
实现一个深比较
function deepEqual(obj1, obj2) {
if (typeof obj1 !== typeof obj2) {
return false;
}
if (typeof obj1 !== 'object' || obj1 === null) {
// 若为基本类型、函数或日期对象,则直接比较值
if (obj1 instanceof Date && obj2 instanceof Date) {
return obj1.getTime() === obj2.getTime();
}
return obj1 === obj2;
}
if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
return obj1.toString() === obj2.toString();
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
for (let key of keys1) {
if (!deepEqual(obj1[key], obj2[key])) {
return false;
}
}
return true;
}
实现千分位
const formatNumber = (num) => {
const str = String(num);
let result = [];
for(let i = str.length - 1, j = 1; i >= 0; i--, j++) {
result.push(str[i]);
if(j % 3 === 0 && i !== 0) {
result.push(',');
}
}
return result.reverse().join('');
};
// 正则实现
const formatNumber = (num) => {
return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
}
const number = 1234567; // 要格式化的数字
console.log(formatNumber(number)); // 输出结果为 "1,234,567"
模拟红绿灯
// 定时器实现
const changeColor = (color) => {
console.log('color:', color);
};
const main = () => {
changeColor('red');
setTimeout(() => {
changeColor('yellow');
setTimeout(() => {
changeColor('green');
setTimeout(main, 1000);
}, 1000);
}, 2000);
};
// Promise 实现
const sleep = (duration) => {
return new Promise(resolve => setTimeout(resolve, duration));
};
const changeColor = async (color, duration) => {
console.log('color:', color);
await sleep(duration);
};
const main = () => {
while(true) {
await changeColor('red', 2000);
await changeColor('yellow', 1000);
await changeColor('green', 3000);
}
}
main()