42 发布订阅模式实现

let bookshop = {}
//有一个列表用来存放函数
bookshop.list = {}

//增加订阅者
bookshop.subscribe = function (key,fun) {
    if (!this.list[key]){
        this.list[key] = []//列表不存在就先初始化
    }
    this.list[key].push(fun)//同一个key支持订阅多次,但是一旦对应key进行发布就会执行里面的所有方法
}

//发布消息

bookshop.publish = function () {
    //取出key对应的订阅列表
    let key = Array.prototype.shift.call(arguments)
    let fns = this.list[key]
    //该列表不存在就返回
    if (!fns || fns.length === 0)return
    //遍历数组 执行这些函数
    fns.forEach(fun => fun.apply(this,arguments))//涉及到this的指向问题需要注意
}

//取消订阅
bookshop.remove = function (key,fun) {
    //取出key对应的订阅列表
    let fns = this.list[key]
     //该列表不存在就返回
    if (!fns)return false
    if (!fun){
        fns && (fns.length = 0)//如果不传对应函数,默认删除该key列表下的全部函数
    }else {
        for (let i = 0; i < fns.length; i++) {
            let tmp = fns[i]
            if (tmp === fun)fns.splice(i,1)
        }
    }
}
function buy(thing,...arg) {
    console.log(arguments)
    console.log(thing)
    console.log(arg)
}
function f() {
    console.log('buy第二次订阅')
}
//先订阅再发布
bookshop.subscribe('buy',buy)
bookshop.subscribe('buy',f)
bookshop.subscribe('sss',buy)

bookshop.publish('buy','math','eng')
bookshop.publish('sss','qqq','ttt')

bookshop.remove('buy',f)
console.log(bookshop.list)