1.compose
function compose(...fn){
if (!fn.length) return (v) => v;
if (fn.length === 1) return fn[0];
return fn.reduce((total,current)=>{
return (args)=>{
total(current(args))
}
})
}
使用案例解析
let x = 10
function fn1 (x) {return x + 1}
function fn2(x) {return x + 2}
function fn3(x) {return x + 3}
function fn4(x) {return x + 4}
// 假设我这里想求得这样的值
let a = fn1(fn2(fn3(fn4(x)))) // 10 + 4 + 3 + 2 + 1 = 20
异步版本
2. settimeout 模拟实现 setinterval(带清除定时器的版本)
function mySettimeout(fn,wait){
let timer = null
function inverval(){
fn()
timer = setTimeout( inverval,wait)
}
inverval()
return {
cancel: function(){
timer && clearTimeout(timer)
}
}
}
var c=mySettimeout(()=>{
console.log(111);
},1000)
我们能反过来使用 setinterval 模拟实现 settimeout 吗?
function myIntevalSettimeout(fn,wait){
let timer = setInteval((){
clearInterval(timer)
fn()
},wait)
return {
cancel: function(){
timer && clearInterval(timer)
}
}
}
var c=myIntevalSettimeout(()=>{
console.log(111);
},1000)
3 发布订阅模式
class EventEmitter {
constructor() {
this.events = {};
}
// 实现订阅
on(type, callBack) {
if (!this.events[type]) {
this.events[type] = [callBack];
} else {
this.events[type].push(callBack);
}
}
// 删除订阅
off(type, callBack) {
if (!this.events[type]) return;
this.events[type] = this.events[type].filter((item) => {
return item !== callBack;
});
}
// 只执行一次订阅事件
once(type, callBack) {
const that = this
function fn() {
callBack();
that.off(type, fn);
}
this.on(type, fn);
}
// 触发事件
emit(type, ...rest) {
this.events[type] &&
this.events[type].forEach((fn) => fn.apply(this, rest));
}
}
4 数组去重
function uniqueArr(arr) {
return [...new Set(arr)];
}
5 数组扁平化
function flatter(arr) {
if (!arr.length) return;
return arr.reduce(
(pre, cur) =>{
return pre.concat(Array.isArray(cur) ?flatter(cur): [cur]
},
[]
);
}
6 寄生组合继承
function Parent(name) {
this.name = name;
this.say = () => {
console.log(111);
};
}
Parent.prototype.play = () => {
console.log(222);
};
function Children(name) {
Parent.call(this);
this.name = name;
}
Children.prototype = Object.create(Parent.prototype);
Children.prototype.constructor = Children;
7 题目描述:JS 实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有两个
class Scheduler {
constructor(limit) {
this.queue = [];
this.maxCount = limit;
this.runCounts = 0;
}
add(time, order) {
const promiseCreator = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(order);
resolve();
}, time);
});
};
this.queue.push(promiseCreator);
}
taskStart() {
for (let i = 0; i < this.maxCount; i++) {
this.request();
}
}
request() {
if (!this.queue || !this.queue.length || this.runCounts >= this.maxCount) {
return;
}
this.runCounts++;
this.queue
.shift()()
.then(() => {
this.runCounts--;
this.request();
});
}
}
const scheduler = new Scheduler(2);
const addTask = (time, order) => {
scheduler.add(time, order);
};
addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");
scheduler.taskStart();
简易版
const fns = [0,1,2,3,4,5].map((item)=>{
return new Promise((resolve)=>{
setTimeout(()=>{
resolve(item)
}, item *100)
})
})
function limtPromise(promises, limit = 2){
let total = promises.length
let index = 0
let queue = []
function run(){
if(index>= total){
return
}
return new Promise((resolve)=>{
queue.push(promises[index])
resolve(promises[index])
}).then((val)=>{
console.log(val, queue,queue.length)
}).finally(()=>{
index ++
queue.shift()
if(index< total) run()
})
}
for(let i = 0;i<limit;i++){
run()
}
}
limtPromise(fns,2)
深度优先遍历(DFS)
function( node ){
let stack = []
let nodes = []
if (node) {
stack.push(node)
while (stack.length) {
//每次取最后一个
let item = stack.pop()
let children = item.children || []
nodes.push(item)
//判断children的长度
for (let i = children.length - 1; i >= 0; i--) {
stack.push(children[i])
}
}
}
return nodes
}
树的递归
function dfs( root,result = [] ){
if(!root){
return
}
root // result.push(root.val) 先序
dfs(root.left,result) // result.push(root.val) 中序
dfs(root.right,result) // result.push(root.val) 后序
}
广度优先遍历(BFS)
function bfs( node ){
let nodes = []
let queue = []
if (node) {
queue.push(node)
while (queue.length) {
//取第一个
let item = queue.shift()
let children = item.children || []
nodes.push(item)
for (let i = 0; i < children.length; i++) {
queue.push(children[i])
}
}
}
return nodes
}
先序遍历(pre)
function pre( root ){
let nodes = []
if(!root){
return []
}
let stack = [root]
let result = []
while (stack.length) {
const node = stack.pop()
result.push(node.val)
if(root.right){
stack.push(root.right)
}
if(root.left){
stack.push(root.left)
}
}
return nodes
}
后序遍历(last)
function last( root ){
let nodes = []
if(!root){
return []
}
let stack = [root]
let result = []
while (stack.length) {
const node = stack.pop()
result.unshift(node.val)
if(root.left){
stack.push(root.left)
}
if(root.right){
stack.push(root.right)
}
}
return nodes
}
中序遍历(mid)
function mid( root ){
let nodes = []
if(!root){
return []
}
let stack = []
while(root || stack.length){
while(root){
stack.push(root)
root = root.left
}
const node = stack.pop()
nodes.push(node.val)
root = node.right
}
return nodes
}
const bt = {
val: 56,
left: {
val: 22,
left: {
val: 10,
left: null,
right: null,
},
right: {
val: 30,
left: null,
right: null,
},
},
right: {
val: 81,
left: {
val: 77,
left: null,
right: null,
},
right: {
val: 92,
left: null,
right: null,
},
},
};
mid(bt) // 10 22 30 56 77 81 92
Promise.resolve(1) .then(()=>{ return 2 }).then(console.log)