Skip to main content
added 1093 characters in body
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

It looks good to me, but your questions are hard to evaluate with such a small snippet.

(1) Efficiency

  1. Efficiency

Basically, what else can you do? You You have to iterate over all registered events.

(2) Organisation

  1. Organisation

SeemsIt seems like a good idea to me. This This way you would have central point for binding events to DOM elements - if i'mI'm understanding your code correctly.

(3) OOP

  1. OOP

(4) Context

  1. Context

This is problematic, but not dramatic! Basically Basically, your .off.off function does not keep the to arrays in sync. -, which is really hard, because events are asynchronous. Consider

Consider this example with simple inheritance:

    <html>
    <body>
    <div id="clickMe">Click Me!</div>
    <script>
    (function(){

        var Hub = Object.create ({});
        //initialize this hub
        Hub.init = function () {
            this.events = {};
            this.contexts = {};
            return this;
        };
        //register a function and context
        Hub.on = function (name, callback, contexts) {
            // create event type if it isn't already and push our callback
            (this.events [name] || (this.events [name] = [])).push (callback);
            (this.contexts [name] || (this.contexts [name] = [])).push (contexts);
 
     
    };
        //un-register a function
        Hub.off = function (name, callback) {
            // if this event type exists, splice out our callback
            console.log(this.events [name].indexOf (callback));
            console.log((this.events));
            console.log(JSON.stringify(this.contexts));
            this.events [name] && this.events [name].splice (this.events [name].indexOf (callback), 1);
            this.contexts [name] && this.contexts [name].splice (this.events [name].indexOf (callback), 1);
            console.log((this.events));
            console.log(JSON.stringify(this.contexts));
        };
        //fire all of a type of functions
        Hub.trigger = function (name) {
          
            if (!this.events [name] || this.events [name].length === 0) return;
            var args = Array.prototype.slice.call (arguments, 1),
         i = 0, event = this.events [name], context = this.contexts [name], l = event.length;
            // if this event type exists, run all the callbacks
            for (; i < l; event [i].apply (context [i++], args));

 
        };


        var Main = {};

        Main.hub = Object.create(Hub);
        Main.hub.init();


        var Foo = {};
        Foo.init = function (name) {

            this.name = name;
            Main.hub.on("lala", this.onClick, this);
    
        };
        Foo.onClick = function Foo_onClick (){

            alert(this.name);
    
        };

        var Bar = Object.create(Foo);;
        Bar.init = function (name) {

            Foo.init.call(this, name);
    
    
        };
        Bar.onClick = function Bar_onClick (){

            Foo.onClick.call(this);
            Main.hub.off("lala", this.onClick);

        };

        var f = Object.create(Foo);
        var b = Object.create(Bar);
        var c = Object.create(Foo);

        f.init("foo");
        b.init("bar");
        c.init("c");

        console.log(Object.is(f,c));

        var clickMe = document.getElementById("clickMe");
        clickMe.addEventListener("click",function(e){

            Main.hub.trigger("lala",e);
    
        });


    }());
    </script>
    </body>
    </html>

Here, calling Hub.offHub.off inside an event callback forces Hub.events.lengthHub.events.length to decrement while ii in Hub.triggerHub.trigger is still incementingincrementing, so event[i]event[i] will be undefined. Also, this.events[name].indexOf(callback)this.events[name].indexOf(callback) will give a different result in the second line:

    this.events [name] && this.events [name].splice (this.events [name].indexOf (callback), 1);
    this.contexts [name] && this.contexts [name].splice (this.events [name].indexOf (callback), 1);

(5) Messes

  1. Messes

Besides (4) i'd, I'd recommend another formatingformatting style, yours. Yours is really hard to read. This This is important, if you consider your product to be maintained in the long run.

(6) Solution for asynchronous calls for .on and .off

  1. Solution for asynchronous calls for .on and .off

Here is a solution for a Hub, which can deal with asynchrounous calls of .on.on and .off.off. I I also made some minor API changes, which strictly (un-)registers only pairs of (callback, context). I'm I'm not certain if this is necessary for unregister, but it markesmakes the API more symmetric.

    var Hub = Object.create ({});
 
    // initializes Hub
    Hub.init = function () {

        this._handlers = {};     // centra registry for custom events
        this._running = false;   // determines if custom evetns ar triggered

    };

    // delays the exectuion of fn while Hub is triggering custom events (_running === true)
    Hub._delay = function Hub_delay (fn) {

        var hub, interval, id;

        hub = this;
        interval = 0;

        // setInterval(fn,0) is the JS equivalent for while(true){}
        // the actual while(true) will certainly kill the process
        id = setInterval(function(){

            if (!this._running) {

                fn.call(hub);
                clearInterval(id);
            
            }
        
        },interval);
    
    };

    // registers the pair (callback, context) for the custom event name
    Hub.on = function Hub_on (name, callback, context) {

        this._delay(function Hub_on_delayed (){

            var handler;
        
            if (!Array.isArray(this._handlers[name])) {

                this._handlers[name] = [];
            
            }

            handler = {};
            handler.callback = callback;
            handler.context  = context;

            this._handlers[name].push(handler);
                    
        });
    
    };

    // unregisters the pair (callback, context) for the custom event name
    Hub.off = function Hub_off (name, callback, context) {

        this._delay(function Hub_off_delayed (){

            if (!Array.isArray(this._handlers[name])) {

                this._handlers[name] = [];
            
            }
        
            console.log(JSON.stringify(this._handlers[name]));
        
            this._handlers[name] = this._handlers[name].filter(function(handler){

            return !(
               return !(handler.callback === callback 
                && handler.context === context);
            );
            
         });

            console.log(JSON.stringify(this._handlers[name]));
        
        });
    
    };

    // triggers all handlers for the custom event name
    Hub.trigger = function Hub_trigger (name) {

        var args, handlers;i, handlers, callback, context, invoke;

        // delay asynchronous registering and unregistering
        this._running = true;

        args = Array.prototype.slice.call (arguments, 1);
        handlers = Array.isArray(this._handlers[name]) ? this._handlers[name] : [];

    handlers.forEach(function(handler){

    for (i = 0; vari callback,< context,handlers.length; invoke;i++) {

            callback = handlerhandlers[i].callback;
            context  = handlerhandlers[i].context; 
        
            // allow invokation only fo valid callbacks and contexts
            invoke = (
                typeof callback === "function" 
                && typeof context !== "undefined"
                && context !== null
            );
        
            if (invoke === true) {

                callback.apply(context, args);
            
            }
        
        }
    });
    
     // allow registering and unregistering
        this._running = false;
    
    };

looks good to me, but your questions are hard to evaluate with such a small snippet.

(1) Efficiency

Basically, what else can you do? You have to iterate over all registered events.

(2) Organisation

Seems like a good idea to me. This way you would have central point for binding events to DOM elements - if i'm understanding your code correctly.

(3) OOP

(4) Context

This is problematic, but not dramatic! Basically your .off function does not keep the to arrays in sync. - which is really hard, because events are asynchronous. Consider this example with simple inheritance:

<html>
<body>
<div id="clickMe">Click Me!</div>
<script>
(function(){

    var Hub = Object.create ({});
    //initialize this hub
    Hub.init = function () {
     this.events = {};
     this.contexts = {};
     return this;
    };
    //register a function and context
    Hub.on = function (name, callback, contexts) {
     // create event type if it isn't already and push our callback
     (this.events [name] || (this.events [name] = [])).push (callback);
     (this.contexts [name] || (this.contexts [name] = [])).push (contexts);
 
     
    };
    //un-register a function
    Hub.off = function (name, callback) {
     // if this event type exists, splice out our callback
     console.log(this.events [name].indexOf (callback));
     console.log((this.events));
     console.log(JSON.stringify(this.contexts));
     this.events [name] && this.events [name].splice (this.events [name].indexOf (callback), 1);
     this.contexts [name] && this.contexts [name].splice (this.events [name].indexOf (callback), 1);
     console.log((this.events));
     console.log(JSON.stringify(this.contexts));
    };
    //fire all of a type of functions
    Hub.trigger = function (name) {
          
     if (!this.events [name] || this.events [name].length === 0) return;
     var args = Array.prototype.slice.call (arguments, 1),
         i = 0, event = this.events [name], context = this.contexts [name], l = event.length;
     // if this event type exists, run all the callbacks
     for (; i < l; event [i].apply (context [i++], args));

 
    };


    var Main = {};

    Main.hub = Object.create(Hub);
    Main.hub.init();


    var Foo = {};
    Foo.init = function (name) {

        this.name = name;
        Main.hub.on("lala", this.onClick, this);
    
    };
    Foo.onClick = function Foo_onClick (){

        alert(this.name);
    
    };

    var Bar = Object.create(Foo);;
    Bar.init = function (name) {

        Foo.init.call(this, name);
    
    
    };
    Bar.onClick = function Bar_onClick (){

        Foo.onClick.call(this);
        Main.hub.off("lala", this.onClick);

    };

    var f = Object.create(Foo);
    var b = Object.create(Bar);
    var c = Object.create(Foo);

    f.init("foo");
    b.init("bar");
    c.init("c");

    console.log(Object.is(f,c));

    var clickMe = document.getElementById("clickMe");
    clickMe.addEventListener("click",function(e){

        Main.hub.trigger("lala",e);
    
    });


}());
</script>
</body>
</html>

Here, calling Hub.off inside an event callback forces Hub.events.length to decrement while i in Hub.trigger is still incementing, so event[i] will be undefined. Also this.events[name].indexOf(callback) will give a different result in the second line:

this.events [name] && this.events [name].splice (this.events [name].indexOf (callback), 1);
this.contexts [name] && this.contexts [name].splice (this.events [name].indexOf (callback), 1);

(5) Messes

Besides (4) i'd recommend another formating style, yours is really hard to read. This is important, if you consider your product to be maintained in the long run.

(6) Solution for asynchronous calls for .on and .off

Here is a solution for a Hub, which can deal with asynchrounous calls of .on and .off. I also made some minor API changes, which strictly (un-)registers only pairs of (callback, context). I'm not certain if this is necessary for unregister, but it markes the API more symmetric.

var Hub = Object.create ({});
 
// initializes Hub
Hub.init = function () {

    this._handlers = {};     // centra registry for custom events
    this._running = false;   // determines if custom evetns ar triggered

};

// delays the exectuion of fn while Hub is triggering custom events (_running === true)
Hub._delay = function Hub_delay (fn) {

    var hub, interval, id;

    hub = this;
    interval = 0;

    // setInterval(fn,0) is the JS equivalent for while(true){}
    // the actual while(true) will certainly kill the process
    id = setInterval(function(){

        if (!this._running) {

            fn.call(hub);
            clearInterval(id);
            
        }
        
    },interval);
    
};

// registers the pair (callback, context) for the custom event name
Hub.on = function Hub_on (name, callback, context) {

    this._delay(function Hub_on_delayed (){

        var handler;
        
        if (!Array.isArray(this._handlers[name])) {

            this._handlers[name] = [];
            
        }

        handler = {};
        handler.callback = callback;
        handler.context  = context;

        this._handlers[name].push(handler);
                    
    });
    
};

// unregisters the pair (callback, context) for the custom event name
Hub.off = function Hub_off (name, callback, context) {

    this._delay(function Hub_off_delayed (){

        if (!Array.isArray(this._handlers[name])) {

            this._handlers[name] = [];
            
        }
        
        console.log(JSON.stringify(this._handlers[name]));
        
        this._handlers[name] = this._handlers[name].filter(function(handler){

            return !(
                handler.callback === callback 
                && handler.context === context
            );
            
         });

        console.log(JSON.stringify(this._handlers[name]));
        
    });
    
};

// triggers all handlers for the custom event name
Hub.trigger = function Hub_trigger (name) {

    var args, handlers;

    // delay asynchronous registering and unregistering
    this._running = true;

    args = Array.prototype.slice.call (arguments, 1);
    handlers = Array.isArray(this._handlers[name]) ? this._handlers[name] : [];

    handlers.forEach(function(handler){

        var callback, context, invoke;

        callback = handler.callback;
        context  = handler.context; 
        
        // allow invokation only fo valid callbacks and contexts
        invoke = (
            typeof callback === "function" 
            && typeof context !== "undefined"
            && context !== null
        );
        
        if (invoke === true) {

             callback.apply(context, args);
            
        }
        
        
    });
    
     // allow registering and unregistering
    this._running = false;
    
};

It looks good to me, but your questions are hard to evaluate with such a small snippet.

  1. Efficiency

Basically, what else can you do? You have to iterate over all registered events.

  1. Organisation

It seems like a good idea to me. This way you would have central point for binding events to DOM elements - if I'm understanding your code correctly.

  1. OOP
  1. Context

This is problematic, but not dramatic! Basically, your .off function does not keep the to arrays in sync, which is really hard because events are asynchronous.

Consider this example with simple inheritance:

    <html>
    <body>
    <div id="clickMe">Click Me!</div>
    <script>
    (function(){

        var Hub = Object.create ({});
        //initialize this hub
        Hub.init = function () {
            this.events = {};
            this.contexts = {};
            return this;
        };
        //register a function and context
        Hub.on = function (name, callback, contexts) {
            // create event type if it isn't already and push our callback
            (this.events [name] || (this.events [name] = [])).push (callback);
            (this.contexts [name] || (this.contexts [name] = [])).push (contexts);
        };
        //un-register a function
        Hub.off = function (name, callback) {
            // if this event type exists, splice out our callback
            console.log(this.events [name].indexOf (callback));
            console.log((this.events));
            console.log(JSON.stringify(this.contexts));
            this.events [name] && this.events [name].splice (this.events [name].indexOf (callback), 1);
            this.contexts [name] && this.contexts [name].splice (this.events [name].indexOf (callback), 1);
            console.log((this.events));
            console.log(JSON.stringify(this.contexts));
        };
        //fire all of a type of functions
        Hub.trigger = function (name) {
          
            if (!this.events [name] || this.events [name].length === 0) return;
            var args = Array.prototype.slice.call (arguments, 1),
         i = 0, event = this.events [name], context = this.contexts [name], l = event.length;
            // if this event type exists, run all the callbacks
            for (; i < l; event [i].apply (context [i++], args));
        };


        var Main = {};

        Main.hub = Object.create(Hub);
        Main.hub.init();


        var Foo = {};
        Foo.init = function (name) {

            this.name = name;
            Main.hub.on("lala", this.onClick, this);
    
        };
        Foo.onClick = function Foo_onClick (){

            alert(this.name);
    
        };

        var Bar = Object.create(Foo);;
        Bar.init = function (name) {

            Foo.init.call(this, name);
    
    
        };
        Bar.onClick = function Bar_onClick (){

            Foo.onClick.call(this);
            Main.hub.off("lala", this.onClick);

        };

        var f = Object.create(Foo);
        var b = Object.create(Bar);
        var c = Object.create(Foo);

        f.init("foo");
        b.init("bar");
        c.init("c");

        console.log(Object.is(f,c));

        var clickMe = document.getElementById("clickMe");
        clickMe.addEventListener("click",function(e){

            Main.hub.trigger("lala",e);
    
        });


    }());
    </script>
    </body>
    </html>

Here, calling Hub.off inside an event callback forces Hub.events.length to decrement while i in Hub.trigger is still incrementing, so event[i] will be undefined. Also, this.events[name].indexOf(callback) will give a different result in the second line:

    this.events [name] && this.events [name].splice (this.events [name].indexOf (callback), 1);
    this.contexts [name] && this.contexts [name].splice (this.events [name].indexOf (callback), 1);
  1. Messes

Besides (4), I'd recommend another formatting style. Yours is really hard to read. This is important, if you consider your product to be maintained in the long run.

  1. Solution for asynchronous calls for .on and .off

Here is a solution for a Hub, which can deal with asynchrounous calls of .on and .off. I also made some minor API changes, which strictly (un-)registers only pairs of (callback, context). I'm not certain if this is necessary for unregister, but it makes the API more symmetric.

    var Hub = Object.create ({});
    // initializes Hub
    Hub.init = function () {

        this._handlers = {};     // centra registry for custom events
        this._running = false;   // determines if custom evetns ar triggered

    };

    // delays the exectuion of fn while Hub is triggering custom events (_running === true)
    Hub._delay = function Hub_delay (fn) {

        var hub, interval, id;

        hub = this;
        interval = 0;

        // setInterval(fn,0) is the JS equivalent for while(true){}
        // the actual while(true) will certainly kill the process
        id = setInterval(function(){

            if (!this._running) {

                fn.call(hub);
                clearInterval(id);
            
            }
        
        },interval);
    
    };

    // registers the pair (callback, context) for the custom event name
    Hub.on = function Hub_on (name, callback, context) {

        this._delay(function Hub_on_delayed (){

            var handler;
        
            if (!Array.isArray(this._handlers[name])) {

                this._handlers[name] = [];
            
            }

            handler = {};
            handler.callback = callback;
            handler.context  = context;

            this._handlers[name].push(handler);
                    
        });
    
    };

    // unregisters the pair (callback, context) for the custom event name
    Hub.off = function Hub_off (name, callback, context) {

        this._delay(function Hub_off_delayed (){

            if (!Array.isArray(this._handlers[name])) {

                this._handlers[name] = [];
            
            }
        
            console.log(JSON.stringify(this._handlers[name]));
        
            this._handlers[name] = this._handlers[name].filter(function(handler){

                return !(handler.callback === callback && handler.context === context);
            
            });

            console.log(JSON.stringify(this._handlers[name]));
        
        });
    
    };

    // triggers all handlers for the custom event name
    Hub.trigger = function Hub_trigger (name) {

        var args, i, handlers, callback, context, invoke;

        // delay asynchronous registering and unregistering
        this._running = true;

        args = Array.prototype.slice.call (arguments, 1);
        handlers = Array.isArray(this._handlers[name]) ? this._handlers[name] : [];

        for (i = 0; i < handlers.length; i++) {

            callback = handlers[i].callback;
            context  = handlers[i].context; 
        
            // allow invokation only fo valid callbacks and contexts
            invoke = (
                typeof callback === "function" 
                && typeof context !== "undefined"
                && context !== null
            );
        
            if (invoke === true) {

                callback.apply(context, args);
            
            }
        
        }
    
        // allow registering and unregistering
        this._running = false;
    
    };
deleted 345 characters in body
Source Link
var Hub = Object.create ({}); 

// initializes Hub
Hub.init = function () {

    this._handlers = {};     // centra registry for custom events
    this._running = false;   // determines if custom evetns ar triggered

};

// delays the exectuion of fn while Hub is triggering custom events (_running === true)
Hub._delay = function Hub_delay (fn) {

    var hub, interval, id;

    hub = this;
    interval = 0;

    // setInterval(fn,0) is the JS equivalent for while(true){}
    // the actual while(true) will certainly kill the process
    id = setInterval(function(){

        if (!this._running) {

            fn.call(hub);
            clearInterval(id);
            
        }
        
    },interval);
    
};

// registers the pair (callback, context) for the custom event name
Hub.on = function Hub_on (name, callback, context) {

    this._delay(function Hub_on_delayed (){

        var handler;
        
        if (!Array.isArray(this._handlers[name])) {

            this._handlers[name] = [];
            
        }

        handler = {};
        handler.callback = callback;
        handler.context  = context;

        this._handlers[name].push(handler);
                    
    });
    
};

// unregisters the pair (callback, context) for the custom event name
Hub.off = function Hub_off (name, callback, context) {

    this._delay(function Hub_off_delayed (){

        if (!Array.isArray(this._handlers[name])) {

            this._handlers[name] = [];
            
        }
        
        console.log(JSON.stringify(this._handlers[name]));
        
        this._handlers[name] = this._handlers[name].filter(function(handler){

            return !(
                handler.callback === callback 
                && handler.context === context
            );
            
        });

        console.log(JSON.stringify(this._handlers[name]));
        
    });
    
};

// triggers all handlers for the custom event name
Hub.trigger = function Hub_trigger (name) {

    var args, i, handlers, callback, context, invoke;handlers;

    // delay asynchronous registering and unregistering
    this._running = true;

    args = Array.prototype.slice.call (arguments, 1);
    handlers = Array.isArray(this._handlers[name]) ? this._handlers[name] : [];

    for handlers.forEach(ifunction(handler){

 = 0; i < handlers.length; i++) { var callback, context, invoke;

        callback = handlers[i]handler.callback;
        context  = handlers[i]handler.context; 
        
        // allow invokation only fo valid callbacks and contexts
        invoke = (
            typeof callback === "function" 
            && typeof context !== "undefined"
            && context !== null
        );
        
        if (invoke === true) {

             callback.apply(context, args);
            
        }
        
        
    });
    
    // allow registering and unregistering
    this._running = false;
    
};
var Hub = Object.create ({});
// initializes Hub
Hub.init = function () {

    this._handlers = {};     // centra registry for custom events
    this._running = false;   // determines if custom evetns ar triggered

};

// delays the exectuion of fn while Hub is triggering custom events (_running === true)
Hub._delay = function Hub_delay (fn) {

    var hub, interval, id;

    hub = this;
    interval = 0;

    // setInterval(fn,0) is the JS equivalent for while(true){}
    // the actual while(true) will certainly kill the process
    id = setInterval(function(){

        if (!this._running) {

            fn.call(hub);
            clearInterval(id);
            
        }
        
    },interval);
    
};

// registers the pair (callback, context) for the custom event name
Hub.on = function Hub_on (name, callback, context) {

    this._delay(function Hub_on_delayed (){

        var handler;
        
        if (!Array.isArray(this._handlers[name])) {

            this._handlers[name] = [];
            
        }

        handler = {};
        handler.callback = callback;
        handler.context  = context;

        this._handlers[name].push(handler);
                    
    });
    
};

// unregisters the pair (callback, context) for the custom event name
Hub.off = function Hub_off (name, callback, context) {

    this._delay(function Hub_off_delayed (){

        if (!Array.isArray(this._handlers[name])) {

            this._handlers[name] = [];
            
        }
        
        console.log(JSON.stringify(this._handlers[name]));
        
        this._handlers[name] = this._handlers[name].filter(function(handler){

            return !(handler.callback === callback && handler.context === context);
            
        });

        console.log(JSON.stringify(this._handlers[name]));
        
    });
    
};

// triggers all handlers for the custom event name
Hub.trigger = function Hub_trigger (name) {

    var args, i, handlers, callback, context, invoke;

    // delay asynchronous registering and unregistering
    this._running = true;

    args = Array.prototype.slice.call (arguments, 1);
    handlers = Array.isArray(this._handlers[name]) ? this._handlers[name] : [];

    for (i = 0; i < handlers.length; i++) {

        callback = handlers[i].callback;
        context  = handlers[i].context; 
        
        // allow invokation only fo valid callbacks and contexts
        invoke = (
            typeof callback === "function" 
            && typeof context !== "undefined"
            && context !== null
        );
        
        if (invoke === true) {

             callback.apply(context, args);
            
        }
        
    }
    
    // allow registering and unregistering
    this._running = false;
    
};
var Hub = Object.create ({}); 

// initializes Hub
Hub.init = function () {

    this._handlers = {};     // centra registry for custom events
    this._running = false;   // determines if custom evetns ar triggered

};

// delays the exectuion of fn while Hub is triggering custom events (_running === true)
Hub._delay = function Hub_delay (fn) {

    var hub, interval, id;

    hub = this;
    interval = 0;

    // setInterval(fn,0) is the JS equivalent for while(true){}
    // the actual while(true) will certainly kill the process
    id = setInterval(function(){

        if (!this._running) {

            fn.call(hub);
            clearInterval(id);
            
        }
        
    },interval);
    
};

// registers the pair (callback, context) for the custom event name
Hub.on = function Hub_on (name, callback, context) {

    this._delay(function Hub_on_delayed (){

        var handler;
        
        if (!Array.isArray(this._handlers[name])) {

            this._handlers[name] = [];
            
        }

        handler = {};
        handler.callback = callback;
        handler.context  = context;

        this._handlers[name].push(handler);
                    
    });
    
};

// unregisters the pair (callback, context) for the custom event name
Hub.off = function Hub_off (name, callback, context) {

    this._delay(function Hub_off_delayed (){

        if (!Array.isArray(this._handlers[name])) {

            this._handlers[name] = [];
            
        }
        
        console.log(JSON.stringify(this._handlers[name]));
        
        this._handlers[name] = this._handlers[name].filter(function(handler){

            return !(
                handler.callback === callback 
                && handler.context === context
            );
            
        });

        console.log(JSON.stringify(this._handlers[name]));
        
    });
    
};

// triggers all handlers for the custom event name
Hub.trigger = function Hub_trigger (name) {

    var args, handlers;

    // delay asynchronous registering and unregistering
    this._running = true;

    args = Array.prototype.slice.call (arguments, 1);
    handlers = Array.isArray(this._handlers[name]) ? this._handlers[name] : [];

    handlers.forEach(function(handler){

        var callback, context, invoke;

        callback = handler.callback;
        context  = handler.context; 
        
        // allow invokation only fo valid callbacks and contexts
        invoke = (
            typeof callback === "function" 
            && typeof context !== "undefined"
            && context !== null
        );
        
        if (invoke === true) {

             callback.apply(context, args);
            
        }
        
        
    });
    
    // allow registering and unregistering
    this._running = false;
    
};
added 293 characters in body
Source Link

Here, calling Hub.off inside an event callback forces Hub.events.length to be reduceddecrement while i in Hub.trigger is still incementing, so event[i] will isbe undefined. Also this.events[name].indexOf(callback) will give a different result in the second line:

this.events [name] && this.events [name].splice (this.events [name].indexOf (callback), 1);
this.contexts [name] && this.contexts [name].splice (this.events [name].indexOf (callback), 1);

Here, calling Hub.off inside an event callback forces Hub.events.length to be reduced while i in Hub.trigger is still incementing, so event[i] will is undefined.

Here, calling Hub.off inside an event callback forces Hub.events.length to decrement while i in Hub.trigger is still incementing, so event[i] will be undefined. Also this.events[name].indexOf(callback) will give a different result in the second line:

this.events [name] && this.events [name].splice (this.events [name].indexOf (callback), 1);
this.contexts [name] && this.contexts [name].splice (this.events [name].indexOf (callback), 1);
added 3298 characters in body
Source Link
Loading
added 15 characters in body
Source Link
Loading
Source Link
Loading