I’m using this basic event system in my Javascript code and I’m trying to document it for my coworkers. I’m not really sure what the difference is in “scope” and “context” in this code. Can anyone help me understand why I even need them both?
this.myClass.prototype.on = function (type, method, scope, context) {
var listeners, handlers, scope;
if ( !(listeners = this.listeners) ) {
listeners = this.listeners = {};
}
if ( !(handlers = listeners[type]) ) {
handlers = listeners[type] = [];
}
scope = (scope ? scope : window);
handlers.push({
method: method,
scope: scope,
context: (context ? context : scope)
});
}
this.myClass.prototype.trigger = function(type, data, context) {
var listeners, handlers, i, n, handler, scope;
if (!(listeners = this.listeners)) {
return;
}
if (!(handlers = listeners[type])){
return;
}
for (i = 0, n = handlers.length; i < n; i++){
handler = handlers[i];
if (context && context !== handler.context) continue;
if (handler.method.call(
handler.scope, this, type, data
)===false) {
return false;
}
}
return true;
}
This code is unnecessarily confusing. The words
contextandscopeare used to mean wrong things. First, let me explain what they should mean to every JavaScript developer:A context of a function is the value of
thisfor that function — i.e. the object the function is called as a method of.You can invoke this function in different contexts like this:
There are many powerful programming patterns that emerge out of this. Function binding (Underscore
bindor jQueryproxy) is one example.Scope on the other hand defines the way JavaScript resolves a variable at run time. There are
only twofour scopes in JavaScript — global, function, block, and module scopes. Moreover, it also deals with something called "scope chain" that makes closures possible.Your
onmethod saves the variablescopeand then uses it in thetriggerfunction as context, which is confusing (it shouldn’t be namedscope— it’s the context):And I have no idea what
thisis in the above call.The
onmethod also accepts acontextwhich defaults to the suppliedscopein casecontextis falsy. Thiscontextis then used to filter the functions to call intrigger.This lets you group your handlers by associating them with an arbitrary object (which they have called
context) and then invoke the entire group by just specifying thecontext.Again, I think this code is overly convoluted and could have been written in a lot simpler way. But then, you shouldn’t need to write your own event emitters like this in the first place — every library has them ready for your use.