手写Call
Function.prototype.myCall = function (thisArg, ...args) {
const fn = this;
thisArg =
thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
thisArg.fn = fn;
const result = thisArg.fn(...args);
delete thisArg.fn;
return result;
};
手写Apply
Function.prototype.myApply = function (thisArg, args) {
const fn = this;
thisArg =
thisArg === null || thisArg === undefined ? Object(thisArg) :window ;
thisArg.fn = fn;
//需要对第二个参数进行一下判断,因为需要传入的是一个数组
args = args || [];
const result = thisArg.fn(...args);
delete thisArg.fn;
return result;
};
手写Bind
Function.prototype.myBind = function (thisArg, ...args) {
const fn = this;
thisArg =
thisArg === null || thisArg === undefined ? window : Object(thisArg);
//bind 调用的时候不会立即执行,而是返回一个函数
return function (...newArgs) {
thisArg.fn = fn;
const result = thisArg.fn(...args, ...newArgs);
delete thisArg.fn;
return result;
};
};
手写柯里化
function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
}
}
};
}
防抖函数
function debounce(func,delay){
let timer = null
const _debounce = function (...args){
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this,args)
},delay)
}
return _debounce
}
立即执行一次防抖
在上一个常规写法的基础上,我们增加了一个传参:immediate
,表示是否开启立即执行;
然后和 timer 变量一样,利用闭包的技术,定义一个isInvoke
,如果为 false 就是还没有立即执行,就去执行一次,并将isInvoke
值改掉
function debounce2(func,delay,immediate = false){
let timer = null
let isInvoke = false
const _debounce = function (...args){
if(timer) clearTimeout(timer)
if(immediate && !isInvoke){
func.apply(this,args)
isInvoke = true
}else {
timer = setTimeout(() => {
func.apply(this,args)
isInvoke = false
},delay)
}
}
return _debounce
}
带取消功能
我们在立即执行一次的基础上,再进行封装,让他支持回调操作,以及取消定时器。
取消定时器很简单,就是给返回的那边变量添加一个属性cancel
,这个 cancel 用来清除定时器,以及通过闭包技术将 timer 和 isInvoke 设置为初始值;
支持回调则只需要在函数执行完毕后,判断函数是否有返回值,如果有,则传入回调函数中执行。
function debounce3(fn, delay, immediate = false, resultCallback) {
let timer = null;
let isInvoke = false;
const _debounce = function (...args) {
if (timer) clearTimeout(timer);
// 判断是否需要立即执行
if (immediate && !isInvoke) {
const result = fn.apply(this, args);
if (resultCallback) resultCallback(result);
isInvoke = true;
} else {
// 延迟执行
timer = setTimeout(() => {
const result = fn.apply(this, args);
if (resultCallback) resultCallback(result);
isInvoke = false;
}, delay);
}
};
// 封装取消功能
_debounce.cancel = function () {
if (timer) clearTimeout(timer);
timer = null;
isInvoke = false;
};
return _debounce;
}
节流函数
function throttle(func,interval){
let lastTime = 0
const _throttle = function (...args){
const nowTime = new Date().getTime()
const remainTime = interval - (nowTime - lastTime)
if(remainTime <= 0){
func.apply(this,args)
lastTime = nowTime
}
}
return _throttle
}
深拷贝
JSON实现
这是通过将对象转换成字符串,然后再转换成对象实现的深拷贝,但是会存在一定的问题,比如:函数
const cloneObj = JSON.parse(JSON.stringify(obj))
递归方式实现
- 首先需要判断传入的对象是否是一个对象类型,如果不是对象类型直接返回即可。
- 如果是对象类型,那么就需要去递归调用 deepCopy 函数。
- 如果他的 key 是一个 Symbol, 就需要 Object.getOwnPropertySymbols 获取到 symbol 的 key,然后去递归调用。
- 然后对传入的数据进行一系列的判断,进行对应的处理。
- 如果是循环引用,就需要用到他的第二个参数 map,初始化是一个 WeakMap 数据,我们每次遍历的时候都会在 map 中将当前这个对象作为 WeakMap 的 key 值存起来,如果发现有一样的存在,那就说明存在递归调用,直接 return 对应的值。
function isObject(value) {
const valueType = typeof value;
return value !== null && (valueType === "object" || valueType === "function");
}
function deepCopy(originValue, map = new WeakMap()) {
// 判断是否是一个Set类型,此处是浅拷贝
if (originValue instanceof Set) {
return new Set([...originValue]);
}
// 判断是否是一个Map类型
if (originValue instanceof Map) {
return new Map([...originValue]);
}
// 如果是Symbol类型
if (typeof originValue === "symbol") {
return Symbol(originValue.description);
}
// 如果是函数类型,那么直接使用同一个函数
if (typeof originValue === "function") {
return originValue;
}
// 判断传入的OriginValue是否是一个对象类型
if (!isObject(originValue)) {
return originValue;
}
// 处理循环引用的问题
if (map.has(originValue)) {
return map.get(originValue);
}
// 判断传入的对象是数组还是对象
const newObject = Array.isArray(originValue) ? [] : {};
// 处理循环引用的问题
map.set(originValue, newObject);
for (const key in originValue) {
newObject[key] = deepCopy(originValue[key], map);
}
// 对symbol的key进行特殊处理
const symbolKeys = Object.getOwnPropertySymbols(originValue);
for (const sKeys of symbolKeys) {
newObject[sKeys] = deepCopy(originValue[sKeys], map);
}
return newObject;
}
异步控制并发数
function limitRequest(urls = [], limit = 3) {
return new Promise((resolve, reject) => {
const len = urls.length;
let count = 0;
// 同时启动limit个任务
while (limit > 0) {
start();
limit -= 1;
}
function start() {
const url = urls.shift(); // 从数组中拿取第一个任务
if (url) {
axios
.post(url)
.then((res) => {
// todo
})
.catch((err) => {
// todo
})
.finally(() => {
if (count == len - 1) {
// 最后一个任务完成
resolve();
} else {
// 完成之后,启动下一个任务
count++;
start();
}
});
}
}
});
}
Promise.all 的实现
Promise.mpAll = function (promiseList = []) {
return new Promise((resolve, reject) => {
const result = []; // 结果数组
promiseList.forEach((p) => {
p.then((res) => {
result.push(res);
if (result.length === promiseList.length) {
resolve(result);
}
}).catch((e) => {
reject(e);
});
});
});
};
实现 instanceof 方法
function myInstanceof(obj, ctor) {
let proto = Object.getPrototypeOf(obj);
let prototype = ctor.prototype;
while (true) {
if (!proto) return false;
if (proto === prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
Comments NOTHING