一、 EventBus
class EventBus {
private events: {
[key]:{fn, isOnce}
}
constructor() {
this.events = {}
}
on (type, fn, isOnce = false) {
const events = this.events
if (events[type] == null) {
events[type] = []
}
events[type].push({ fn, isOnce})
}
once (type,fn) {
this.on(type, fn, true)
}
off (type, fn) {
if (!fn) {
this.events[type] = []
} else {
const fnList = this.events[type]
if (fnList) {
this.events[type] = fnList.filter(item => item.fn != fn)
}
}
}
emit(type, ...args) {
const fnList = this.events[type]
if (fnList == null) return
this.events[type] = fnList.filter(item => {
const { fn, isOnce } = item
fn(...args)
if (!isOnce) return true
return false
})
}
}
二、lazyman
class lazyman {
private name
private tasks = []
constructor( name ) {
this.name = name
setTimeout(() => {
this.next()
})
}
private next() {
const task = this.tasks.shift()
if (task) task()
}
eat(food) {
const task = () => {
console.info(`${this.name} eat ${food}`)
this.next()
}
this.tasks.push(task)
return this
}
sleep (seconds) {
const task = () => {
console.info(`${this.name} 开始睡觉`)
setTimeout(() => {
console.info(`${this.name} 已经睡完了 ${seconds}s,开始执行下一个任务`)
this.next()
}, seconds * 1000)
}
this.tasks.push(task)
return this
}
}
三、LRU 最近最少使用
class LRUCache {
private length
private data = new Map()
constructor(length) {
if (length < 1) throw new Error(`invalid length`)
this.length = length
}
set(key, value) {
const data = this.data
if (data.has(key)) {
data.delete(key)
}
data.set(key,value)
if (data.size > this.length) {
//超出容量,删除 Map最老元素
const delKey = data.keys().next().value
data.delete(delKey)
}
}
get(key) {
const data = this.data
if (!this.data.has(key)) return null
const value = data.get(key)
data.delete(key)
data.set(key, value)
return value
}
}
四、数组扁平化
function flatten(arr) {
let res = []
arr.forEach(item => {
res = res.concat(item)
});
return res
}
//数组深度扁平化
function flattenDeep(arr) {
let res = []
arr.forEach(item => {
if (Array.isArray(item)) {
const flatItem = flattenDeep(item)
res = res.concat(flatItem)
} else {
res = res.concat(item)
}
})
return res
}
五、获取数据类型
function getType(obj) {
const originType = Object.prototype.toString.call(obj)
const spaceIndex = originType.indexOf('')
const type = originType.slice(spaceIndex + 1, -1)
return type.toLowerCase()
}
六、深拷贝考虑到 Map Set WeakMap WeakSet等特殊类型
function CloneDeep(obj, map = new WeakMap()) {
if (typeof obj !== 'object' || obj == null) return obj
const objFromMap = map.get(obj)
if (objFromMap) return objFromMap
let target = {}
map.set(obj, target)
//枚举法
if (obj instanceof Map) {
target = new Map()
obj.forEach((v,k) => {
const v1 = CloneDeep(v,map)
const k1 = CloneDeep(k,map)
target.set(k1, v1)
})
}
if (obj instanceof Set) {
target = new Set()
obj.forEach(v => {
const v1 = CloneDeep(v,map)
target.add(v1)
})
}
if (obj instanceof Array) {
target = obj.map(item => CloneDeep(item, map))
}
if (const key in obj) {
const val = obj[key]
const val1 = CloneDeep(val, map)
target[key] = val1
}
return target
}
七、数组转树
/*
const arr = [
{ id: 1, name: ‘部门A’, parentId: 0 }, // 0 代表顶级节点,无父节点
{ id: 2, name: ‘部门B’, parentId: 1 },
{ id: 3, name: ‘部门C’, parentId: 1 },
{ id: 4, name: ‘部门D’, parentId: 2 },
{ id: 5, name: ‘部门E’, parentId: 2 },
{ id: 6, name: ‘部门F’, parentId: 3 },
]
*/
interface IArrayItem {
id: number
name: string
parentId: number
}
interface ITreeNode {
id: number
name: string
children?: ITreeNode[]
}
function convert(arr: IArrayItem[]): ITreeNode | null {
const idToTreeNode: Map<number, ITreeNode> = new Map()
let root = null
arr.forEach(item => {
const { id, name, parentId } = item
const treeNode:ITreeNode = {id, name}
idToTreeNode.set(id,treeNode)
const parentNode = idToTreeNode.get(parentId)
if(parentNode) {
if (parentNode.children == null) parentNode.children = []
parentNode.children.push(treeNode)
}
if (parentId === 0) root = treeNode
})
return root
}
八、树转数组
/*
//
const obj = {
id: 1,
name: ‘部门A’,
children: [
{
id: 2,
name: ‘部门B’,
children: [
{ id: 4, name: ‘部门D’ },
{ id: 5, name: ‘部门E’ }
]
},
{
id: 3,
name: ‘部门C’,
children: [
{ id: 6, name: ‘部门F’ }
]
}
]
}
*/
function convert1(root: ITreeNode): IArrayItem[] {
const nodeToParent: Map<ITreeNode, ITreeNode> = new Map()
const arr: IArrayItem[] = []
const queue: ITreeNode[] = []
queue.unshift(root)
while (queue.length > 0) {
const curNode = queue.pop()
if (curNode == null) break
const { id, name, children = []} = curNode
const parentNode = nodeToParent.get(curNode)
const parentId = parentNode?.id || 0
const item = { id, name, parentId}
arr.push(item)
children.forEach(child => {
nodeToParent.set(child,curNode)
queue.unshift(child)
})
}
return arr
}