I've been using the module pattern for a while, but recently have started wanting to mix in functions and properties into them to increase code re-use. I've read some good resources on the subject, but still am a bit uncertain as to the best approach. Here is a module:
var myModule = function () {
var privateConfigVar = "Private!";
//"constructor"
function module() {}
module.publicMethod = function () {
console.log('public');
}
function privateMethod1() {
console.log('private');
}
return module;
}
And here is a mixin object:
var myMixin = function () {};
Mixin.prototype = {
mixinMethod1: function () {
console.log('mixin private 1');
},
mixinMethod2: function () {
console.log('mixin private 2');
}
};
Ideally, I'd like to mix-in some methods from other objects as private methods and some as public methods, so that I could call some "extend" function, with a param as "private"/"public". So, that
mixin(myModule, myMixin, "private");
makes the myMixin methods available within myModule by just calling mixinMethod1() and have correct scope, and:
mixin(myModule, myMixin, "public");
makes the myMixin methods available within myModule by calling module.mixinMethod1() and have correct scope
I've tried using a method that copies properties from one prototype to another, I've tried the underscore extend method to copy properties of the object from one to to the other, and various things in between. I think I'm a bit turned around regarding scope and prototypes at this point, and would love some direction as to how best to do mixins like this when using the module pattern. Note that it doesn't matter what the object myMixin looks like (whether adding functions to the prototype, or a module itself), I'm just trying to figure out some way to make it work.
Thank!
The
with
keyword can be very usefull to define a scope, but it has also some drawbacks (it is by the way forbidden in strict mode).Using the
with
keyword, you can define a private variableprivateScope
within the body of your module, that would contain all your provate methods :Your mixin will use the
definePrivateFunction
we just defined to add private methods to the private scope :The following code should work fine:
That's impossible. You cannot modify a scope by calling a function, especially not from outside. See also Is it possible to
import
variables in JavaScript? for the design reasons of that.So, what can you do?
From outside the module
Nothing to the private scope(s) of
module
functions. And you cannot use the private functions of the module, obviously. You can extend its prototype with methods (which is the most common), you can even decorate its constructor function. Within those, you can use your own private functions, either completely static ones or class-specific ones.From within the module
Using the mixin in the module code itself can allow for much greater flexibility.
With such an interface, it becomes easy to construct a class that is using this as a mixin (not inheriting from it):
However, the mixin will never have access to the private class variables, nor can it present a private, class-specific API. Still, we can use dependency injection to provide that access explicitly (and having a mixin factory in effect):
Not all techniques shown above need to be used in every mixin, just choose the ones you need. Not all possible techniques are shown in the above examples, also :-) The mixin pattern can be applied onto a plain module or inside its declaration as well, the above examples have only shown classes with prototypes.
For a few good examples, and a theoretical distinction between (stateless) Traits, (stateful) Mixins and their "privileged" counterparts, have a look at this presentation.
As it already has been mentioned, there is no way of achieving exactly this goal.
And referring to scope ... this is a closed address space created by functions. Except for closures, scope only is available during a function's runtime within this function's body. It never ever can be manipulated/spoofed.
The term one is looking for is context. JavaScript, being in many ways highly dynamic, is build upon late binding (the object/target/context a method is called on gets evaluated/looked up at runtime) and two kinds of delegation. Context gets delegated either automatically by "walking the prototype chain" or explicitly by one of both call methods which every function object does provide - either
call
orapply
.Thus JavaScript already at language core level does offer a function based Mixin pattern that is mightier than any of the available
extend(s)
ormixin
implementations for it provides delegation for free and is able of passing around state which almost every of the blamed helpers does lack unless there was effort of implementing this feature again in a rather roundabout fashion (or ass-backwards to put it bluntly).Bergi for his explanation already earned the bounties. Within his answer's last paragraph there is a link to resources of mine that already got outdated 3 month after giving the referred talk. Due of not having enough reputation points, I'm not able to comment his answer directly. For this I'll take the chance pointing now to the latest state of my personal research and understanding of »The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins«
Back again answering the OP's question.
I'm going to change the two first given code examples from the assumed module pattern and the rather exemplarily provided mixin code base towards a plain constructor function and what I'm meanwhile tempted to call a "proxified" and/or "bicontextual" mixin in order to boil down the mechanics of delegating two different target/context objects at once. Thus demonstrating a pure function based mixin pattern that might come closest to what the OP tries to achieve.
This special pattern also is the underlying base for composing pure function based Traits that rely on conflict resolution functionality provided by "proxified" Mixins that won't expose this functionality into public.
And for not ending up that theoretical there will be a "real world example", composing a
Queue
module out of various reusable mixins that entirely worship the approach of DRY. It also should answer the OP's question about how to achieve encapsulation and exposition build only upon the module pattern and function based mixin composition.