ES6 - 如何获取特定上下文的数组项(函数)

时间:2017-03-26 14:49:42

标签: javascript oop design-patterns ecmascript-6 publish-subscribe

给定使用ES6的发布 - 订阅模式如下(从https://davidwalsh.name/pubsub-javascript中提取):

class PubSub {
    constructor() {
        this.handlers = [];
    }

    subscribe(event, handler, context) {
        if (typeof context === 'undefined') {
            context = handler;
        }
        {
            if (this.getHandler(event, handler) == null) {
                this.handlers.push({event: event, handler: handler.bind(context), key: Guid()});
            }
        }
    }

    unsubscribe(event, handler) {
        let filteredHandler = this.getHandler(event, handler);
        if (filteredHandler != null) {
            let idx = this.handlers.indexOf(filteredHandler);
            if (idx > -1) {
                this.handlers.splice(idx, 1);
            }
        }
    }

    publish(event, args) {
        this.handlers.forEach(topic => {
            if (topic.event === event) {
                topic.handler(args)
            }
        })
    }

    getHandler(event, handler) {
        if (this.handlers == null || this.handlers.length < 1) {
            return null;
        }

        let filtered = null;

        this.handlers.forEach(topic => {
            if (topic.event === event && topic.handler === handler) {
                filtered = topic;
            }
        });

        return filtered;
    }

    getNumOfSubsribers() {
        if (this.handlers != null && this.handlers.length > 0) {
            return this.handlers.length;
        }

        return 0;
    }
}

订阅和发布方法有效。但是,getHandler和unsubscribe方法不能按预期工作(getHandler似乎返回null)。我试图搜索但无法得到满意的解决方案来解决这个问题(不确定绑定到给定上下文的函数如何从数组中过滤掉)。

我在代码中做错了什么?请在getHandler上告诉我,并取消订阅部分代码。

感谢某种帮助。

1 个答案:

答案 0 :(得分:2)

这段代码在某些方面很奇怪。

getHandler不起作用的原因是handler上推送的对象的handlers属性不是传入的函数;这是在该函数上调用bind的结果。格式正确,这是subscribe

subscribe(event, handler, context) {
    if (typeof context === 'undefined') {
        context = handler;
    }
    {
        if (this.getHandler(event, handler) == null) {
            this.handlers.push({
                event: event,
                handler: handler.bind(context),  // ** NOTE **
                key: Guid()
            });
        }
    }
}

根据定义,该值永远不会等于原始值。

相反,它应该包括原始处理程序,以便稍后检查它。让我们摆脱毫无意义的独立块:

subscribe(event, handler, context) {
    if (typeof context === 'undefined') {
        context = handler;
    }
    if (this.getHandler(event, handler) == null) {
        this.handlers.push({
            event: event,
            handler: handler.bind(context),
            originalHandler: handler,        // ***
            key: Guid()
        });
    }
}

现在,getHandler可以查找与originalHandler的匹配项。当我们在那里时,让我们在找到处理程序而不是继续进行时停止循环,并使用语义上合适的Array#find

getHandler(event, handler) {
    if (this.handlers == null || this.handlers.length < 1) {
        return null;
    }

    let filtered = this.handlers.find(topic => topic.event === event && topic.originalHandler === handler);
    return filtered;
}

代码还有其他问题(例如,如果没有提供context,则将处理程序绑定到自身),但完整的代码审查超出范围;以上是getHandler不起作用的原因,也就是为什么unsubscribe不起作用的原因。有了这个修复,unsubscribe也应该有用(虽然搜索两次似乎很奇怪)。