实现链式调用
重点是return this 和任务队列顺序
class Task {
constructor(){
this.list=[];
this.logNum=0;
this.waitNum=0;
setTimeout(()=>{
this.next();
})
}
log(n){
this.logNum=n;
const fn=()=>{
let num=n
console.log(num)
this.next()
}
this.list.push(fn)
return this;
}
wait(n){
this.waitNum=n
const fn=()=>{
setTimeout(()=>{
console.log(`等待了${n}秒`)
this.next()
},n*1000)
}
this.list.push(fn)
return this;
}
next(){
const fn=this.list.shift()
fn&&fn();
}
}
const t=new Task()
// console.log(t)
t.log(1).log(2).wait(3).log(4).wait(2).wait(3).log(6)
使用promise实现:
class U {
constructor() {
this.promise = Promise.resolve();
}
console(val) {
this.promise = this.promise.then(() => {
console.log(val);
});
return this;
}
setTimeout(wait) {
this.promise = this.promise.then(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, wait);
});
});
return this;
}
}
const u = new U();
u.console("breakfast")
.setTimeout(3000)
.console("lunch")
.setTimeout(3000)
.console("dinner");
实现发布订阅模式
class EventEmitter {
constructor() {
//存储事件
this.cache = {}
}
//订阅事件的方法on(eventName, callback)
on(name, fn) {
if (this.cache[name]) {
this.cache[name].push(fn)
} else {
this.cache[name] = [fn]
}
}
//移除事件
off(name, fn) {
let tasks = this.cache[name]
if (tasks) {
const index = tasks.findIndex(f => f === fn || f.callback === fn)
if (index >= 0) {
tasks.splice(index, 1)
}
}
}
//触发事件的方法emit(eventName, callback)
emit(name, once = false, ...args) {
if (this.cache[name]) {
// 创建副本(一层深拷贝),如果回调函数内继续注册相同事件,会造成死循环
let tasks = this.cache[name].slice()
for (let fn of tasks) {
fn(...args)
}
//是否只执行一次
if (once) {
delete this.cache[name]
}
}
}
}
// 简单使用
let newEvent = new EventEmitter()
newEvent.on('event1', function(arg) {
console.log('事件1', arg)
})
newEvent.on('event2', function(arg) {
console.log('事件2', arg)
})
newEvent.emit('event1',false, {name: 'anyway'})
newEvent.emit('event2', false ,{age: '28'})
//事件1 { name: 'anyway' }
//事件2 { age: '28' }
柯里化函数的实现
柯里化函数的定义:将多参数的函数转换成单参数的形式。
柯里化函数实现的原理:利用闭包原理在执行可以形成一个不销毁的作用域,然后把需要预先处理的内容都储存在这个不销毁的作用域中,并且返回一个最少参数函数。
第一种:固定传入参数,参数够了才执行
/**
* 实现要点:柯里化函数接收到足够参数后,就会执行原函数,那么我们如何去确定何时达到足够的参数呢?
* 柯里化函数需要记住你已经给过他的参数,如果没给的话,则默认为一个空数组。
* 接下来每次调用的时候,需要检查参数是否给够,如果够了,则执行fn,没有的话则返回一个新的 curry 函数,将现有的参数塞给他。
*
*/
// 待柯里化处理的函数
let sum = (a, b, c, d) => {
return a + b + c + d
}
let curry = (fn, ...args) => {
return (...newArgs)=>{
let resArgs=args.concat(newArgs);
//fn.length 返回函数的形参个数
if(fn.length===resArgs.length){
return fn(...args,...resArgs)
}else{
return curry(fn,...resArgs)
}
}
};
var sumPlus = curry(sum)
sumPlus(1)(2)(3)(4)
sumPlus(1, 2)(3)(4)
sumPlus(1, 2, 3)(4)
第二种:不固定传入参数,随时执行
/**
* 当然了,柯里化函数的主要作用还是延迟执行,执行的触发条件不一定是参数个数相等,也可以是其他的条件。
* 例如参数个为0的情况,那么我们需要对上面curry函数稍微做修改
*/
// 待柯里化处理的函数
let sum = arr => {
return arr.reduce((a, b) => {
return a + b
})
}
let curry = (fn, ...arr) => { // arr 记录已有参数
return (...args) => { // args 接收新参数
if (args.length === 0) { // 参数为空时,触发执行
return fn(...arr, ...args)
} else { // 继续添加参数
return curry(fn, ...arr, ...args)
}
}
}
var sumPlus = curry(sum)
sumPlus(1)(2)(3)(4)()
sumPlus(1, 2)(3)(4)()
sumPlus(1, 2, 3)(4)()
add(1)(2)(3)=6
function add(x) {
var sum = x;
var res = function (x) {
sum = sum + x;
return res;
};
// 此处是在函数上挂载一个方法,
res.out = function () {
return sum;
};
return res;
}
sleep函数
第一种方式:使用Promise + setTimeout实现
function sleep(time) {
return new Promise(resolve => {
console.log(resolve)
setTimeout(resolve, time)
})
}
sleep(10000).then(res => {
console.log(`sleep exe ending!`)
})
第二种方式:使用callback回调
function sleep(time, callback) {
return new Promise(resolve => setTimeout(callback, time))
}
sleep(3000, () => {
console.log(`sleep exe ending!`)
})