Extending the Revealing Module Pattern – Why is this a bad idea?
invalid-arg.github.io
invalid-arg.github.io
/** @private */
MyClass.prototype.foo_ = function() {}I do dislike this pattern as I find the code is less structured, harder to debug, and less performant than attaching functions on the prototype. This outweighs the benefits of encapsulation to me.
The only scenario I can even think of where it would maybe possibly matter would be a tight loop where you are doing little else except just accessing properties.
But yes, I also have not been bitten by this. Its just something I've read about how the v8 engine works (and makes sense intuitively). I agree you shouldn't base coding style decisions soley on hearing one way is faster, but I think its a minor point and worth noting.
Edit: a link! https://news.ycombinator.com/item?id=2991904
If you're concerned about coworkers calling your private methods, the right tool is coding standards and code review. If you can't trust your coworkers to use good judgement even in the face of those things, you have bigger problem :) On the other hand, if your goal in using this pattern was to protect your private methods from bad people on the internet, you probably need to rethink your assumption that it is possible to sandbox JavaScript without interpreter-level support.
We do use (function () { ... })() in specific situations when we need to create a new scope, but this would typically only occur in framework code rather than application code (especially once the `linker` branch lands, which lets you declare specific exports and imports at the package level, and then the `meteor` asset build tool wires them up for you so that each package gets just the global environment it asked for.)
Also for now, we prefer to use prototypal inheritance directly rather than use a class library. On the latter, our perspective is that if Meteor developers want to use a class library, they should be able to pick their favorite rather than be stuck with ours.
This isn't to say that having documentation on what you consider to be the API is a bad idea though. Omitting the functions you don't want or expect people to use is good for public facing docs.
I'm not completely ready to call this an anti-pattern. There's no reason to expose local methods of an Object to the parent scope if they aren't needed. I'm sure that in some cases this could cause the memory footprint of an Object to be larger than desired by preventing garbage collection. Anyway, I would have factored your code more like this:
var PseudoClass = function(_args){
// guarantee that "this" is what we expect
if( this === window ){ // use global for non-browser implementations
return new PseudoClass(_args);
}
// private variables are local
var private = function() {;
this.value = 2;
};
// public variables are on prototype
this.constructor.prototype.value = 1; // I'd prolly use a local var and a getter for this
this.constructor.prototype.public = function(){
private.call(this); // force scope for private methods
};
// testing access (only added when necessary)
this.constructor.prototype.privateMembers = {
"private":function(){ private.call(this) }
};
};
There's no "self" here, but there are two pieces of insurance around scope.
First is the condition that forces the "new" keyword. (This could be written to test against instanceof the function name, but generally problems occur when users forget new, not when they force the scope to be wrong. Last I checked, this is how jQuery tests it too.)
Second is calling the private methods with the call() method of the function, allowing us to keep the scope from defaulting to global/window. Sure, you are forced to put these in to avoid errors, but this is programming. If you would like it to throw an error when this === window within private(), just add it. I didn't because a) I'm lazy and b) once the PseudoClass private methods are all called, I would end up removing the un-thrown errors and the privateMembers property before compressing for staging/production to keep size down.Using a variable like "self" is quite clear in this context and I've seen it done thousands of times. I just wanted to show that using "this" is still possible.
Javascript is a funny language. I often find myself wondering if this was the intended structure of the language as it takes advantage of many of the key elements (closure scopes & prototype) while abstractly appearing like simple Java (or C#). Sure in a perfect world, the wrangling of "this" wouldn't need to be done. I'd say the unpredictable value of "this" in different contexts is the biggest fail of Javascript. I programmed ActionScript (including AS1) for many years and this (pun intended) is the biggest mindf*ck I've come across when regarding them in comparison (considering they're both based on ECMA script). Hope there was something helpful to you in this.
Or you can just do this.foo = foo; this.value = value; at the end instead of returning an Object.