Function scoping offers the only privacy in JavaScript.
So the canonical:
function Ctor(dep1, dep2) {
this._dep1 = dep1;
this._dep2 = dep2;
}
Ctor.prototype.foo = function() {
// use this._dep1/2...
}
...is problematic in that it offers no encapsulation for the injected dependencies.
An alternative (albeit slightly different in terms of location of foo
) that offers real encapsulation might be:
function factory(dep1, dep2) {
return {
foo: partial(foo, dep1, dep2), // or use bind (partial could be a library fn for partial application)
};
}
function foo(dep1, dep2) {
// use dep1/2
}
But I rarely see this pattern. Is there a good reason to not use the latter?
Simple: why?
"Privacy" is terrifically overrated. It doesn't hide anything from anyone who really wants it. Having "protected" or "private" members is purely for the programmer's benefit, specifically to indicate how a particular member is supposed to be used (this here is a public API, this here is not so please don't touch it unless you know what it does). That's all. A naming convention like starting underscores is perfectly enough to implement that. If a member name starts with an underscore, don't touch it, unless you know what you're doing.
There's no intrinsic need to bend over backwards further than that.
You already state the advantages of the second pattern. The disadvantages are:
you must either group methods by visibility (even if the private method is intimately related with a public one, but barely related to other private methods), or repeat all public methods in the object literal (which doesn't work well with jsdoc).
the code introduces a separate function object for every instance of your class, which sacrifices some performance (this usually doesn't matter, but sometimes might)
unlike private modifiers in many programming languages, this encapsulation can not be circumvented, even if misapplied and I really know what I am doing (historically, JavaScript has been an environment where anything goes, and many attribute its success to this extensibility)