function loadCss(url, callback) {
return new Promise((resolve) => {
var node = document.createElement("link");
node.type = "text/css";
node.rel = "stylesheet";
node.href = url;
node.onerror = node.onload = function () {
resolve();
isFunction(callback) && callback();
};
document.head.appendChild(node);
});
}
function loadJs(url, callback, attr) {
if (!isFunction(callback)) {
attr = callback;
callback = null;
}
return new Promise((resolve, reject) => {
var script = document.createElement("script");
script.type = "text/javascript";
if (isObject(attr)) {
Object.keys(attr).forEach((key) => {
if (attr.hasOwnProperty(key)) {
script.setAttribute(key, attr[key]);
}
});
}
if (script.readyState) {
script.onreadystatechange = function () {
if (script.readyState == "loaded" || script.readyState == "complete") {
script.onreadystatechange = null;
isFunction(callback) && callback();
resolve();
}
};
} else {
script.onload = function () {
isFunction(callback) && callback();
resolve();
};
}
script.onerror = function () {
reject();
};
script.src = url;
document.head.appendChild(script);
});
}
加减乘除
/**
* 加法
* @param {...any} n
*/
function add(...n) {
return n.reduce((ji, item) => {
let l1 = (ji.toString().split(".")[1] || "").length;
let l2 = (item.toString().split(".")[1] || "").length;
let l = Math.pow(10, Math.max(l1, l2));
return (ji * l + item * l) / l;
});
}
/**
* 乘法
* @param {...any} n
*/
function mul(...n) {
return n.reduce((ji, item) => {
let n1 = (ji.toString().split(".")[1] || "").length;
let n2 = (item.toString().split(".")[1] || "").length;
return (
(ji * Math.pow(10, n1) * item * Math.pow(10, n2)) / Math.pow(10, n1 + n2)
);
});
}
/**
* 除法
* @param {...any} n
*/
function div(...n) {
return n.reduce((ji, item) => {
let n1 = (ji.toString().split(".")[1] || "").length;
let n2 = (item.toString().split(".")[1] || "").length;
return (
(ji * Math.pow(10, n1) * item * Math.pow(10, n2)) / Math.pow(10, n1 + n2)
);
});
}
/**
* 减法
* @param {...any} n
*/
function sub(...n) {
return n.reduce((ji, item) => {
let l1 = (ji.toString().split(".")[1] || "").length;
let l2 = (item.toString().split(".")[1] || "").length;
let n = Math.max(l1, l2);
let l = Math.pow(10, n);
return ((ji * l - item * l) / l).toFixed(n);
});
}
深拷贝
// 拷贝一个数组
let nums = [10, 1, 2, 3, 5, 7, 13];
console.log(Array.from(nums).sort((a, b) => a - b));
console.log([...nums].sort((a, b) => a - b));
console.log(nums.slice().sort((a, b) => a - b));
console.log(nums.map((v) => v).sort((a, b) => a - b));
console.log(nums.filter((v) => true).sort((a, b) => a - b));
console.log(Object.assign([], nums).sort((a, b) => a - b));
console.log("nums", nums); // [10, 1, 2, 3, 5, 7, 13]
const deepClone = (o, cached) => {
if (o instanceof Object) {
let cache = new Map();
let result;
if (o instanceof Function) {
if (o.prototype) {
result = function () {
return o.apply(this, arguments);
};
} else {
result = (...args) => {
return o.call(undefined, ...args);
};
}
} else if (o instanceof Array) {
result = [];
} else if (o instanceof Date) {
return +new Date(o);
} else if (o instanceof RegExp) {
result = new RegExp(o.source, o.flags);
} else {
result = {};
}
for (const key in o) {
if (Object.hasOwnProperty.call(o, key)) {
if (cached && cached.has(o)) {
result[key] = cached.get(key);
} else {
let val = deepClone(o[key], cache);
cache.set(key, val);
result[key] = val;
}
}
}
return result;
} else {
return o;
}
};
const a = {
date: new Date(2020, 0, 1, 20, 30, 0),
reg: /\s/g,
number: 1,
str: "h1",
empty1: undefined,
empty2: null,
array: [
{ name: "yue", arge: 18 },
{ name: "heizi", arge: 18 },
],
obj: {
name: "yue",
arge: 18,
},
f1: (a, b) => a + b,
f2: function (a, b) {
return a + b;
},
};
a.self = a;
const a2 = deepClone(a);
// console.log(a2);
// console.log(a2.f2(1, 2));
// console.log(a2.f1(1, 2));
对象全等 looseEqual
function isObject(value) {
var type = typeof value;
return value != null && (type == "object" || type == "function");
}
/**
* form vue
* Check if two values are loosely equal - that is,
* if they are plain objects, do they have the same shape?
*/
function looseEqual(a, b) {
if (a === b) return true;
const isObjectA = isObject(a);
const isObjectB = isObject(b);
if (isObjectA && isObjectB) {
try {
const isArrayA = Array.isArray(a);
const isArrayB = Array.isArray(b);
if (isArrayA && isArrayB) {
return (
a.length === b.length &&
a.every((e, i) => {
return looseEqual(e, b[i]);
})
);
} else if (a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime();
} else if (!isArrayA && !isArrayB) {
const keysA = Object.keys(a);
const keysB = Object.keys(b);
return (
keysA.length === keysB.length &&
keysA.every((key) => {
return looseEqual(a[key], b[key]);
})
);
} else {
return false;
}
} catch (e) {
return false;
}
} else if (!isObjectA && !isObjectB) {
// 判断基本类型 number、string、boolean、null、undefined、Symbol、BigInt
return String(a) === String(b);
} else {
return false;
}
}
const a = {
weight: 8,
fields: [
{
name: "全额缴费",
value: 0,
},
{
name: "按月缴费",
value: 1,
},
],
};
const b = {
weight: "8",
fields: [
{
name: "全额缴费",
value: 0,
},
{
name: "按月缴费",
value: 1,
},
],
};
console.log(looseEqual(a, b));
function pipe(...funcs) {
return function (result) {
let list = funcs.slice();
while (list.length > 0) {
// 从列表中取第一个函数并执行
result = list.shift()(result);
}
return result;
};
}
// function compose(...funcs) {
// return function (result) {
// let list = funcs.slice();
// while (list.length > 0) {
// // 从列表中取第一个函数并执行
// result = list.pop()(result);
// }
// return result;
// };
// }
function compose(...funcs) {
return function (value) {
return funcs.reduceRight((reducer, reducer) => reducer(state), value);
};
}
/* function pipe(...funcs) {
return function (value) {
return funcs.reduce((state, reducer) => reducer(state), value);
};
} */
const join = (x, y) => `${x}${y}`;
const firstUpperCase = (str) => {
return str.slice(0, 1).toLocaleUpperCase() + str.slice(1);
};
const camelize = (str) => {
return str.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : ""));
};
const componentName = pipe(firstUpperCase, camelize);
const componentName2 = compose(camelize, firstUpperCase);
console.log(componentName("insure-step-by-step")); // InsureStepByStep
console.log(componentName2("uk-insurance-mall")); // UkInsuranceMall
算法
找出现最多次数的字母
let str = "configureyourdevicetousewhistleasitsHTTPandHTTPSproxyonIP";
let str2 = "aabbcbc";
// o、e 出现了 5 次
function getMaxString(string) {
const map = {};
let max = 1;
let maxKeys = [];
for (let i = 0; i < string.length; i++) {
let key = string[i];
map[key] ? map[key]++ : (map[key] = 1);
if (map[key] > max) {
max = map[key];
maxKeys = [key];
} else if (map[key] === max) {
maxKeys.push(key);
}
}
console.log("最大值存在多个", maxKeys.join("、") + "出现了 " + max + "次");
return [max, maxKeys];
}
getMaxString(str); // 5, ['e','o']
getMaxString(str2); // 3, ['b']
function randomStr(length) {
let array = [];
const strPool = "AAABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (let i = 0; i < length; i++) {
array[i] = strPool[Math.floor(Math.random() * strPool.length)];
}
return array.join("");
}
var str = randomStr(1000000);
console.log(`目标字符串长度为${str.length}`);
function findByRegex() {
console.time("findByRegex");
let orderStr = str.split("").sort().join("");
// let orderStr = str;
let letter = "";
let max = 0;
orderStr.replace(/([a-zA-Z])\1*/g, (subStr, char) => {
if (subStr.length > max) {
letter = char;
max = subStr.length;
}
});
console.log(`出现次数最多的字母是${letter},出现了${max}次`);
console.timeEnd("findByRegex");
}
function findByLoop() {
console.time("findByLoop");
let letter = "";
let max = 0;
let result = [];
let datum = "A".charCodeAt();
for (let i = 0; i < str.length; i++) {
let index = str.charCodeAt(i) - datum;
result[index] = (result[index] || 0) + 1;
}
for (let i = 0; i < result.length; i++) {
if (result[i] > max) {
max = result[i];
letter = String.fromCharCode(datum + i);
}
}
console.log(`出现次数最多的字母是${letter},出现了${max}次`);
console.timeEnd("findByLoop");
}
function getMaxString(string) {
console.time("getMaxString");
const map = {};
let max = 1;
let maxKeys = [];
for (let i = 0; i < string.length; i++) {
let key = string[i];
map[key] ? map[key]++ : (map[key] = 1);
if (map[key] > max) {
max = map[key];
maxKeys = [key];
} else if (map[key] === max) {
maxKeys.push(key);
}
}
console.log("最大值存在多个", maxKeys.join("、") + "出现了 " + max + "次");
console.timeEnd("getMaxString");
return [max, maxKeys];
}
findByRegex();
findByLoop();
getMaxString(str);
二分查找
// 先递增后递减数组求减求最大值
const arr1 = [0, 1, 4, 7, 5];
const arr2 = [1, 6, 5, 3, 2];
const arr3 = [1, 2, 3, 4, 5, 6, 7, 9, 3, 2];
function getMax(params) {
let begin = 0;
let end = params.length - 1;
while (begin <= end) {
let mid = Math.floor(begin + (end - begin) / 2);
console.log(mid);
let element = params[mid];
if (element > params[mid - 1] && element > params[mid + 1]) {
console.log("第" + (mid + 1) + "个" + element + "最大");
return element;
// 当前比右边的数小,向右走
} else if (element < params[mid + 1]) {
begin = mid + 1;
// 当前比左边的数小,相左走
} else if (element < params[mid - 1]) {
end = mid - 1;
}
}
return -1;
}
// console.log(getMax(arr1));
// console.log(getMax(arr2));
console.log(getMax(arr3));
大数相加
function add(a, b) {
let maxLength = Math.max(a.length, b.length);
//用0去补齐长度
a = a.padStart(maxLength, 0); //"0009007199254740991"
b = b.padStart(maxLength, 0); //"1234567899999999999"
//定义加法过程中需要用到的变量
let t = 0;
let f = 0; //"进位"
let sum = "";
for (let i = maxLength - 1; i >= 0; i--) {
t = parseInt(a[i]) + parseInt(b[i]) + f;
f = Math.floor(t / 10);
sum = (t % 10) + sum;
}
if (f == 1) {
sum = "1" + sum;
}
return sum;
}
const add = (a, b) => {
const maxLength = Math.max(a.length, b.length);
let overflow = false;
let sum = "";
for (let i = 1; i <= maxLength; i++) {
const ai = a[a.length - i] || "0";
const bi = b[b.length - i] || "0";
let ci = parseInt(ai) + parseInt(bi) + (overflow ? 1 : 0);
overflow = ci >= 10;
ci = overflow ? ci - 10 : ci;
sum = ci + sum;
}
sum = overflow ? "1" + sum : sum;
return sum;
};
console.log(add("111", "99"));
console.log(add("9007199254740991", "1234567899999999999"));
const p = () =>
new Promise((resolve, reject) =>
setTimeout(() => {
let a = Math.random();
let flag = a > 0.1 ? 0 : 1;
console.log(flag);
flag === 1 ? resolve(flag) : reject(flag);
}, 1000)
);
/* Promise.retry = function (promiseFn, times = 3) {
return new Promise(async (resolve, reject) => {
while (times--) {
try {
let ret = await promiseFn();
resolve(ret);
break;
} catch (error) {
if (!times) reject(error);
}
}
});
}; */
/* Promise.retry = function (promiseFn, times = 3) {
return new Promise((resolve, reject) => {
let count = 0;
let action = function () {
promiseFn()
.then(resolve)
.catch((err) => {
count++;
if (count >= times) {
reject(err);
} else {
action();
}
});
};
action();
});
}; */
Promise.retry = function (asyncFn, times = 3) {
let count = 0;
function executeFn() {
return new Promise((resolve, reject) => {
resolve(asyncFn());
})
.then((res) => {
return Promise.resolve(res);
})
.catch((err) => {
count++;
if (count >= times) {
return Promise.reject(err);
} else {
return executeFn();
}
});
}
return executeFn();
};
Promise.retry(p, 3).then(() => {
console.log("okkk");
});
任务中断
批量执行异步任务,有任务返回 false 就中断执行并返回结果。
let asyncFn = (val) => {
return new Promise((resolve) => {
setInterval(() => {
resolve(val);
}, 1000);
});
};
let tasks = [true, false, false].map((v) => () => asyncFn(v));
// 基础 for 循环
/* async function run() {
for (let i = 0; i < tasks.length; i++) {
const task = tasks[i];
let res = await task();
if (!res) {
return false;
}
}
return true;
} */
// for of
async function run() {
for (const task of tasks) {
let res = await task();
if (!res) {
return false;
}
}
return true;
}
async function main() {
let result = await run();
console.log("result", result);
}
main(); // result false
工具方法
load
加减乘除
深拷贝
对象全等 looseEqual
对象取键 get
merge
枚举
队列
栈
函数式
函数记忆
升级版
函数柯里化
函数管道 compose、pipe
算法
找出现最多次数的字母
二分查找
大数相加
玩转异步
基础模拟 Promise Class
await 错误捕获
Promise 同步与异步
调试
异步重试
按时间重试
按次数重试
实现
Promie.retry
,成功后 resolve 结果,失败后重试,尝试超过一定次数才真正 reject任务中断
批量执行异步任务,有任务返回 false 就中断执行并返回结果。
其他
reduce 经典用法
padStart 方法重写
Proxy api
动态导入