export function flattenArray(arr: any[]): any[] {
return arr.reduce((acc, val) => {
if (Array.isArray(val)) acc = acc.concat(flattenArray(val));
else acc.push(val);
return acc;
}, []);
}
export function flattenArray2(arr: any[], level: number): any[] {
let count = 0;
function getVal(a: any[]) {
const res: any[] = [];
for (const item of a) {
if (Array.isArray(item) && level >= count++) {
res.push(...getVal(item));
} else {
res.push(item);
}
}
return res;
}
return getVal(arr);
}
export function getType(value: any) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
export function New<T>(constructor: Function, ...args: any[]): T {
const obj = Object.create(constructor.prototype);
constructor.apply(obj, args);
return obj;
}
export function visiteNode(node: Node) {
if (node instanceof Text) {
const t = node.textContent?.trim();
if (t) {
console.info('文本节点---', t);
}
}
if (node instanceof HTMLElement) {
console.info('标签节点---', node.tagName.toLowerCase());
}
}
export function deepthFistTravse(root: Node) {
if (!root) return false;
visiteNode(root)
const childNodes = root.childNodes;
childNodes.forEach((node) => {
deepthFistTravse(node);
})
}
export function breadthFistTravse(root: Node) {
if (!root) return false;
const queue: Node[] = [root];
while (queue.length) {
const node = queue.shift();
if (!node) continue;
visiteNode(node);
if (node) {
for (let i = 0; i < node.childNodes.length; i++) {
queue.push(node.childNodes[i]);
}
}
}
}
export class LazyMan {
private name: string;
private task: Function[] = []
constructor(name: string) {
this.name = name;
setTimeout(() => {
this.next();
}, 100);
}
private next() {
const task = this.task.shift();
task && task();
}
eat(food: string) {
const eatTask = () => {
console.log(`${this.name} is eating ${food}`);
this.next();
};
this.task.push(eatTask);
return this;
}
sleep(time: number) {
const sleepTask = () => {
console.log(`${this.name} is sleeping.`);
setTimeout(() => {
console.log(`${this.name} is wake up`);
this.next();
}, time * 1000);
};
this.task.push(sleepTask);
return this;
}
}
export function curry(fn: Function) {
let _args: any[] = [];
const fnParamsLen = fn.length;
const calc = function (this: any, ...args: any[]) {
_args = [..._args, ...args];
if (_args.length >= fnParamsLen) {
return fn.apply(this, _args.slice(0, fnParamsLen));
} else {
return calc;
}
}
return calc;
}
export function myInstanceof(instance: any, origin: any): boolean {
if (instance == null) return false;
const type = typeof instance;
if (type !== 'object' && type !== 'function') {
return false;
}
let tmpInst = Object.getPrototypeOf(instance);
while (tmpInst) {
if (tmpInst === origin.prototype) {
return true;
}
tmpInst = Object.getPrototypeOf(tmpInst);
}
return false;
}
Function.prototype.myBind = function (ctx: any, ...newArgs: any[]) {
const self = this;
return function (...args: any[]) {
return self.apply(ctx, newArgs.concat(args));
}
}
Function.prototype.myCall = function (ctx: any, ...args: any[]) {
if (ctx === null || ctx === undefined) {
ctx = globalThis
}
if (typeof ctx !== 'object') {
ctx = new Object(ctx);
}
const fnKey = Symbol('fn');
ctx[fnKey] = this;
const result = ctx[fnKey](...args);
delete ctx[fnKey];
return result;
}
export class EventBus {
private events: { [key: string]: { fn: Function, isOnce: boolean }[] } = {};
on(type: string, fn: Function, isOnce: boolean) {
this.events[type] = this.events[type] || [];
this.events[type].push({
fn,
isOnce
});
}
once(type: string, fn: Function) {
this.on(type, fn, true);
}
off(type: string, fn?: Function) {
if (!this.events[type]) return;
if (!fn) {
this.events[type] = [];
} else {
const index = this.events[type].findIndex(item => item.fn === fn);
index !== -1 && this.events[type].splice(index, 1);
}
}
emit(type: string, ...args: any[]) {
if (!this.events[type]) return;
this.events[type] = this.events[type].filter(item => {
item.fn(...args);
return !item.isOnce;
});
}
}
export class LRUCache {
private len: number;
private data: Map<any, any> = new Map();
constructor(len: number) {
this.len = len;
}
set(key: any, value: any) {
if (this.data.has(key)) {
this.data.delete(key);
this.data.set(key, value);
} else {
this.data.set(key, value);
}
if (this.data.size > this.len) {
this.data.delete(this.data.keys().next().value);
}
}
get(key: any) {
if (this.data.has(key)) {
const value = this.data.get(key);
this.data.delete(key);
this.set(key, value);
return value;
} else {
return null;
}
}
}
interface IDoubleNode {
val: any;
key: any;
next?: IDoubleNode | null;
prev?: IDoubleNode | null;
}
export class LRUCache2 {
private capacity: number;
private dataLen: number = 0;
private data: { [key: string]: IDoubleNode } = {};
private head: IDoubleNode | null = null;
private tail: IDoubleNode | null = null;
constructor(capacity: number) {
if (capacity < 1) throw new Error('capacity must be greater than zero');
this.capacity = capacity;
}
moveToTail(curNode: IDoubleNode) {
if (curNode === this.tail) return;
const prev = curNode.prev;
const next = curNode.next;
if (prev) {
if (next) {
prev.next = next;
} else {
delete prev.next;
}
}
if (next) {
if (prev) {
next.prev = prev;
} else {
delete next.prev;
}
if (this.head === curNode) {
this.head = next;
}
}
delete curNode.next;
delete curNode.prev;
if (this.tail) {
this.tail.next = curNode;
curNode.prev = this.tail;
}
this.tail = curNode;
}
tryClean() {
while (this.dataLen > this.capacity) {
if (!this.head) {
throw new Error('head is null');
}
const nextNode = this.head.next;
const delKey = this.head.key;
if (!nextNode) {
throw new Error('next node is null');
}
delete nextNode.prev;
delete this.head.next;
this.head = nextNode;
delete this.data[delKey];
this.dataLen--;
}
}
set(key: any, value: any) {
const curNode = this.data[key];
if (!curNode) {
const newNode = { key, val: value };
this.moveToTail(newNode);
this.data[key] = newNode;
this.dataLen++;
if (this.dataLen === 1) {
this.head = newNode;
}
} else {
curNode.val = value;
this.moveToTail(curNode);
}
this.tryClean();
}
get(key: any): any {
const curNode = this.data[key];
if (!curNode) return null;
if (curNode !== this.tail) {
this.moveToTail(curNode);
}
return curNode.val;
}
}
export function deepClone(obj: any, wmap: WeakMap<any, any> = new WeakMap()) {
let result: any = {};
if (obj === null) return obj;
if (typeof obj !== 'object') return obj;
if (wmap.has(obj)) return wmap.get(obj);
wmap.set(obj, result);
if (obj instanceof Map) {
result = new Map();
for (let [key, value] of obj) {
result.set(deepClone(key, wmap), deepClone(value, wmap));
}
return result;
}
if (obj instanceof Set) {
result = new Set();
for (let value of obj) {
result.add(deepClone(value, wmap));
}
return result;
}
if (Array.isArray(obj)) {
result = [];
for (let i = 0; i < obj.length; i++) {
result[i] = deepClone(obj[i], wmap);
}
return result;
}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key], wmap);
}
}
return result;
}
interface ITreeNode {
id: number;
name: string;
children?: ITreeNode[];
}
export function covertArrToTree(arr: any[]) {
const treeIdMap: Map<number, ITreeNode> = new Map();
let rootNode: ITreeNode | null = null;
arr.forEach((item) => {
const node: ITreeNode = {
id: item.id,
name: item.name,
};
const parent = treeIdMap.get(item.parentId);
if (parent) {
parent.children = parent.children || [];
parent.children.push(node);
}
if (item.parentId === 0) {
rootNode = node;
}
treeIdMap.set(item.id, node);
});
return rootNode;
}
export function covertTreeToArr(obj: any) {
const pidMap: Map<number, any> = new Map();
const result: any[] = [];
const queue: any[] = [obj];
while (queue.length) {
const node = queue.shift();
const item = {
id: node.id,
name: node.name,
parentId: pidMap.get(node.id) || 0,
};
result.push(item);
if (node.children) {
for (let child of node.children) {
queue.push(child);
pidMap.set(child.id, node.id);
}
}
}
return result;
}