Since the original post, I have explored further regarding this pattern. In an effort to fix one self-percieved flaw (the lack of ability of prototype methods to access private object members), I have revised this Class pattern. As no one has responded regarding the pattern, I am offering a bounty.
In general, only people with a high level of expertise in JavaScript will probably be able to review this to my requirements. To be clear, here are my requirements:
- I am not looking for a review that utilizes convention as its primary argument.
- Code style should only be a factor, if and only if it can keep the pattern intact:
- All scopes must maintain their accessibility to the other scopes.
- Clear and Concise review regarding potential security issues.
- Verifiable performance statistics (if this is one of your review's arguments).
- Supplemental code and reasoning (for instance, where one would use Object.freeze() or places to consider validation).
- Other patterns to consider, if they can meet the scoping guidelines.
Please, keep in mind that this is an abstract pattern. The pattern works, though the code utilizes pseudocode. Code Edit Class private member privateAccess was changed to this.privateAccess to allow for proper inheritance. There will be another edit to account for exploits of this.
[var | Namespace.]ClassName = (function(Class) {
/* Any static(class-wide) privates go here */
var privateMethod = function() {
return 'I\'m doing something privately';
};
/* The class prototype */
Class.prototype = {}; // or new BaseClass();
Class.prototype.propertyName = function(value) {
var returnValue;
// Unlock private Access
this.privateAccess = true;
// Forward the property access
returnValue = this.privateAccessFunction('propertyName', value);
// Lock it back up again!
delete this.privateAccess;
return returnValue;
};
// Lock the function, so it can't be modified.
Object.freeze(Class.prototype.propertyName);
// Optional: Lock the prototype
/* The class constructor */
Class.instance = function(config) {
// Fail if called without using new!
if (!this instanceof Class)
return undefined;
// So derivative classes don't share privates
if (config) {
var myPrivateMembers = {
propertyName: 'value'
};
Object.defineProperty(
this,
'privatePropertyAccess',
{
//This is the actual Getter/Setter
// P.S. I like chainable properties
value: function(name, value) {
// Protects our function from call(obj)
if (!this.privateAccess || !this instanceof Class)
return undefined;
if (name !== undefined && typeof name === 'string') {
if (value !== undefined) {
privateMembers[name] = value;
return this;
}
return privateMembers[name];
}
return undefined;
},
writable: false,
configurable: false,
enumerable: false
}
);
}
};
// So that we get the Class back
return Class;
}([Namespace.]ClassName = [Namespace.]ClassName || function(config){
if (this instanceof [Namespace.]ClassName)
return [Namespace.]ClassName.instance.call(this, config);
}));
After much research, I've determined that I really like this pattern for the following reasons:
Debugging (in Chrome)
- ClassNames are clear without having to open the object (even for private Classes).
- They remain this way even after minifying with several libraries.
Object Advantages
- Object has access to Object Privates & Static/Class Privates
- Object controls which private data to expose to Prototype Methods.
- Private data may be locked/unlocked on a per method basis.
Prototype Advantages
- Prototype Methods have safe access to its own private members.
- Prototype Methods are chainable.
- Prototype Methods are only defined once. (if modifying the prototype in a constructor, it gets modified every time the constructor runs)
- Prototype Methods have access to static private members.
Known Disadvantages
- Classes are a little heavier.
- PrivateAccess is not thread-safe(the privateAccess variable is static). This should be fine for synchronous code, however.
- Derivative classes must conform to a similar pattern (privateAccess and accessPrivateMember())
Final Note
In all of my years, this class pattern is the closest I've ever gotten to classical OOP, without losing any benefit that ECMAScript/JavaScript has. Additionally, it doesn't seem to require additional extension functions. Further, it doesn't inhibit the use of any other type of inheritance that JS provides. While this wasn't the goal, at the time, it is certainly a consideration for me.
Update regarding Edit and Meta: (Since I cannot comment on the meta attached to this becuase my bounty threw me below the 50 pt requirement). After the first answer indicating an extra brace, it was indeed removed and the code is working. Some notes on the meta attached: The code here is not the same as the orginal question and was edited, despite the comments in the Meta. This is not an issue of refusal to fix code. Transferring an in practice and currently researched code piece to an abstract pseudocode like pattern sometimes has issues. This one had a curly brace.