There is a pattern that's often called "Delegate", which addresses this issue.
In javascript, a not-too-fancy implementation might look something like this:
/** class Delegate **/
var Delegate = function(thisRef, funcRef, argsArray) {
this.thisRef=thisRef;
this.funcRef=funcRef;
this.argsArray=argsArray;
}
Delegate.prototype.invoke = function() {
this.funcRef.apply(this.thisRef, this.argsArray);
}
/** static function Delegate.create - convenience function **/
Delegate.create = function(thisRef, funcRef, argsArray) {
var d = new Delegate(thisRef, funcRef, argsArray);
return function() { d.invoke(); }
}
In your example, you would use it like this:
this.b = function() {
Z( Delegate.create(this, this.c) );
}
you could also write functions that expect to receive a Delegate:
function Z( d ) {
d.invoke();
}
then, in A
, your impl of b
becomes:
this.b = function() {
var d = new Delegate(this, this.c);
Z( d );
SomeOtherFunc( d );
}
The Delegate
just provides a simple, consistent way of encapsulating the this
reference (which you've called self
), within an object instance that can be dealt with like any other object instance. It's more readable, and it keeps you from having to pollute your function scope with superfluous variables like self
. A fancier delegate implementation could have its own methods and other related state. It's also possible to build the delegate in such a way that it helps to minimize some scope-related memory management problems (though the code I've shown here is definitely not an example of that).