为eventListener类

时间:2018-05-08 13:29:49

标签: javascript

我正在尝试实现一个有四种方法的自定义Emitter类。所有工作除了一次。

我需要实施返回的'once'方法 事件名称的当前订阅者数量。

once方法的当前行为是事件正在添加但未被删除或调用。

class Emitter {

    constructor() {
        //Arrays of objects
        this.events = {};
    }

    on(eventName, callBack) {
        //If the event name is not a string data type throw error
        if (typeof eventName !== 'string') throw 'Event name is not a String';

        // If the callback is not a function data type throw error
        if (typeof callBack !== 'function') throw 'Callback is not a Function';

        let event = this.events[eventName];
        // If eventName is already defined then push the callback, else create
        !event ? this.events[eventName] = [callBack] : event.push(callBack);

        //this.events[eventName] ? this.events[eventName].push(callBack) : this.events[eventName] = [callBack];

        return this.events[eventName].length;
    }

    off(eventName, callBack) {
        //If there are two arguments provided then, callback must be there!
        let isCallBackDefined = arguments.length === 2 ? true : false;

        //If the event name is not a string data type throw error
        if (typeof eventName !== 'string') throw 'Event name is not a String';

        // If the function is not a function data type (if provided) throw error
        if (isCallBackDefined && typeof callBack !== 'function') throw 'Callback is not a Function';

        // First get the correct event
        let event = this.events[eventName];
        // Check that the event exists and it has the callback registered
        if (event) {
            //  if no callback function provided, then all functions are unsubscribed
            //  event has no callbacks left, delete the event
            if (isCallBackDefined === false) {
                delete this.events[eventName];
            } else {
                // if it is registered then unregister it!
                const index = event.indexOf(callBack);
                // If the callback is in the array then remove it
                if (index > -1) {
                    event.splice(index, 1);
                }
                // if the event has no callbacks left, delete the event
                if (event.length === 0) {
                    delete this.events[eventName];
                }
            }
        }

        return (this.events[eventName] || []).length;
    }

    trigger(eventName, ...args) {
        if (typeof eventName !== 'string') throw TypeError('Event name is not a String');
        let listeners;

        // If the event exists; create a shallow copy
        if (this.events[eventName]) {
            listeners = this.events[eventName].slice();
        }

        // Check that the event exists and it has the callback registered
        if (listeners) {
            for (let callBack of listeners) {
                callBack.apply(this, args);
            }
        }

        return listeners ? true : false;
    }

    once(event, fn) {
        //If the event name is not a string data type throw error
        if (typeof event !== 'string') throw 'Event name is not a String';

        // If the callback is not a function data type throw error
        if (typeof fn !== 'function') throw 'Callback is not a Function';

        function g() {
            this.off(event, g);
            fn.apply(this, arguments);
        }

        g.fn = fn;
        this.on(event, g);
    };
}

1 个答案:

答案 0 :(得分:0)

您只需返回事件名称的回调数。我在控制台中添加了一些“测试”,以便您确认。

class Emitter {

    constructor() {
        //Arrays of objects
        this.events = {};
    }

    on(eventName, callBack) {
        //If the event name is not a string data type throw error
        if (typeof eventName !== 'string') throw 'Event name is not a String';

        // If the callback is not a function data type throw error
        if (typeof callBack !== 'function') throw 'Callback is not a Function';

        let event = this.events[eventName];
        // If eventName is already defined then push the callback, else create
        !event ? this.events[eventName] = [callBack] : event.push(callBack);

        //this.events[eventName] ? this.events[eventName].push(callBack) : this.events[eventName] = [callBack];

        return this.events[eventName].length;
    }

    off(eventName, callBack) {
        //If there are two arguments provided then, callback must be there!
        let isCallBackDefined = arguments.length === 2 ? true : false;

        //If the event name is not a string data type throw error
        if (typeof eventName !== 'string') throw 'Event name is not a String';

        // If the function is not a function data type (if provided) throw error
        if (isCallBackDefined && typeof callBack !== 'function') throw 'Callback is not a Function';

        // First get the correct event
        let event = this.events[eventName];
        // Check that the event exists and it has the callback registered
        if (event) {
            //  if no callback function provided, then all functions are unsubscribed
            //  event has no callbacks left, delete the event
            if (isCallBackDefined === false) {
                delete this.events[eventName];
            } else {
                // if it is registered then unregister it!
                const index = event.indexOf(callBack);
                // If the callback is in the array then remove it
                if (index > -1) {
                    event.splice(index, 1);
                }
                // if the event has no callbacks left, delete the event
                if (event.length === 0) {
                    delete this.events[eventName];
                }
            }
        }

        return (this.events[eventName] || []).length;
    }

    trigger(eventName, ...args) {
        if (typeof eventName !== 'string') throw TypeError('Event name is not a String');
        let listeners;

        // If the event exists; create a shallow copy
        if (this.events[eventName]) {
            listeners = this.events[eventName].slice();
        }

        // Check that the event exists and it has the callback registered
        if (listeners) {
            for (let callBack of listeners) {
                callBack.apply(this, args);
            }
        }

        return listeners ? true : false;
    }

    once(event, fn) {
        //If the event name is not a string data type throw error
        if (typeof event !== 'string') throw 'Event name is not a String';

        // If the callback is not a function data type throw error
        if (typeof fn !== 'function') throw 'Callback is not a Function';

        function g() {
            this.off(event, g);
            fn.apply(this, arguments);
        }

        g.fn = fn;
        this.on(event, g);

        return this.events[event].length;
        // ^^ Return the current number of subscribers
    };
}



// Test it!
let fnCallCount = 0;
let fnArgs = null;
const fn = (...args) => {
  fnCallCount += 1;
  fnArgs = args;
}

const sut = new Emitter();
sut.trigger('test', 1, 2, 3);

console.log("Number of subscribers ('test'):", sut.once('test', fn));  // Expecting 1
console.log("Number of subscribers ('next'):", sut.once('next', ()=>{}));  // Expecting 1
console.log("Number of subscribers ('next'):", sut.once('next', ()=>{}));  // Expecting 2
console.log("Call count after first event:", fnCallCount);  // Expecting 1
console.log("Call args:", fnArgs);        // Expecting [1,2,3]

sut.trigger('test', 1, 2, 3);
console.log("Call count after second event:", fnCallCount);  // Expecting 1