I have a set of JavaScript "classes" where a base class defines functions that are then shared by an inherited class. It is working, and it is set up like this:
var ThingA = function(name) {
this.name = name;
};
ThingA.prototype = {
sayHi: function() {
alert('Hi, ' + this.name + '!');
}
};
var ThingB = function() {
ThingA.call(this, 'Charlie');
};
ThingB.prototype = new ThingA();
ThingB.prototype.constructor = ThingB;
var instanceOfB = new ThingB();
instanceOfB.sayHi(); // alerts 'Hi, Charlie!'
For reasons that are outside of my control, my company prefers to follow this pattern when writing JavaScript:
SomeClass = function() {
// "Private" functions go here
function somePrivateMethod() {
...
}
return {
// "Public" methods go here
somePublicMethod: function() { ... }
};
}();
Now, this is fine as far as things go, and it works well for many situations. But it is more of a functional style. There is only one "class" instance, and everything is static.
I've been asked to modify my working code to more closely match the style my company prefers. So my question is, there a way to inherit from a class that is wrapped inside a factory class? It would look something like this:
FactoryClassA = function() {
var ThingA = function(name) {
this.name = name;
};
ThingA.prototype = {
sayHi: function() {
alert('Hi, ' + this.name + '!');
}
};
return {
createThingA: function(name) {
return new ThingA(name);
}
};
}();
FactoryClassB = function() {
// Define a ThingB class that inherits from ThingA somehow
return {
createThingB: function() {
return new ThingB();
}
};
}();
var instanceOfB = FactoryClassB.createThingB();
instanceOfB.sayHi(); // should alert 'Hi, Charlie!'
Is there a way to define ThingB wrapped in FactoryClassB that inherits from ThingA wrapped in FactoryClassA? Thanks to this question, I know that I'm not going to be able to do it exactly like this. I am thinking of using a method to extend a given class ... somehow?
This answer seems close, but I'm having trouble figuring out the details of how to modify that example to fit with the specifics of my situation. I am willing to bend my company's usual pattern a little bit, but can I at least get closer to it?
UPDATE 1
In response to Adam's comment to just add a parameter to the factory class, here's where I'm stuck:
ThingB.prototype = new ThingA();
ThingB.prototype.constructor = ThingB;
I can't figure out how to adapt these lines to make it work if I just pass in a parameter to the factory class method.
Below is what (I believe) you're looking for:
FactoryClassA = function() {
var ThingA = function(name) {
this.name = name;
};
ThingA.prototype = {
sayHi: function() {
console.log('Hi, ' + this.name + '!');
}
};
// Add the constructor back to the prototype
// (see explanation below)
ThingA.prototype.constructor = ThingA;
return {
createThingA: function(name) {
return new ThingA(name);
}
};
}();
FactoryClassB = function() {
// Bootstrapping:
// Capture the instance, as we'll need it to set up the prototype
var baseInstance = new FactoryClassA.createThingA();
// Capture the constructor
var baseConstructor = baseInstance.constructor;
// Keep a reference to the base prototype
var baseProto = baseConstructor.prototype;
function ThingB(name) {
// Call base constructor, along with our args
baseConstructor.call(this, name);
};
ThingB.prototype = baseInstance;
ThingB.prototype.constructor = ThingB;
ThingB.prototype.sayHi = function() {
console.log('here I am');
// call the base class `sayHi`
baseProto.sayHi.call(this);
};
return {
createThingB: function(name) {
return new ThingB(name);
}
};
}();
// Testing
var foo = FactoryClassB.createThingB("Indeed");
foo.sayHi();
// Output:
// here I am
// hi indeed
Explanation:
in FactoryClassA, this line is necessary:
ThingA.prototype.constructor = ThingA;
Note that every prototype in JS is automatically created with a reference to its constructor. For example, when you do:
function T(){}
T.prototype already has a property called constructor which points back to T.
However, in your implementation of ThingA, you reset the entire prototype, by doing ThingA.prototype = { ... }. Therefore, you now have lost the reference to its constructor. In 99% of cases it is ok, and won't have any negative side effects (which is probably why most developers tend to forget it). However, in the case of inheritance, it may be necessary.
Now, within FactoryClassB, we need to do some bootstrapping:
var baseInstance = new FactoryClassA.createThingA();
var baseConstructor = baseInstance.constructor;
var baseProto = baseConstructor.prototype;
Observe the last two lines, as they are pivotal to achieving inheritance in this design pattern. First, since ThingA's constructor is accessible via the prototype (ThingA.prototype.constructor = ThingA), then it means that given an instance of ThingA, we can directly retrieve its constructor. Since the constructor is the function itself, and since every function has a reference to its prototype, we can keep a reference of ThingA.prototype with baseConstructor.prototype.
Next is the critical part, where we set up the inheritance chain:
function ThingB(name) {
// Call the base constructor
baseConstructor.call(this, name);
};
ThingB.prototype = baseInstance;
ThingB.prototype.constructor = ThingB;
The last line above is quite important, as it tells the prototype what its constructor is, otherwise it would still point to ThingA.
There you have it - prototypal inheritance.
Side note:
You can probably see how the above can get quite tedious, a little grotesque, and repetitive. Ergo, you might want to consider an inheritance library like Fiber.js which follows the encapsulation pattern you desired (along with some bonuses like mixins and decorators). Disclaimer: I authored the library.
Related
Coming from a C++ / Objective-C background, I'm trying to learn how to correctly and efficiently reproduce the patterns of inheritance and encapsulation in Javascript. I've done plenty of reading (Crockford etc.) and while there are plenty of examples of how to achieve one or the other, I'm struggling with how to combine them without introducing significant negatives.
At the moment, I have this code:
var BaseClass = (function() {
function doThing() {
console.log("[%s] Base-class's 'doThing'", this.name);
}
function reportThing() {
console.log("[%s] Base-class's 'reportThing'", this.name);
}
return function(name) {
var self = Object.create({});
self.name = name;
self.doThing = doThing;
self.reportThing = reportThing;
return self;
}
}());
var SubClass = (function(base) {
function extraThing() {
console.log("[%s] Sub-class's 'extraThing'", this.name);
}
function doThing() {
console.log("[%s] Sub-class's replacement 'doThing'", this.name);
}
return function(name) {
// Create an instance of the base object, passing our 'name' to it.
var self = Object.create(base(name));
// We need to bind the new method to replace the old
self.doThing = doThing;
self.extraThing = extraThing;
return self;
}
}(BaseClass));
It mostly does what I want:
// Create an instance of the base class and call it's two methods
var base = BaseClass("Bert");
base.doThing(); // "[Bert] Base-class's 'doThing'"
base.reportThing(); // "[Bert] Base-class's 'reportThing'"
var other = BaseClass("Fred");
// Create an instance of the sub-class and call it's three methods (two from the base, one of it's own)
var sub = SubClass("Alfred");
sub.doThing(); // "[Alfred] Sub-class's replacement 'doThing'"
sub.extraThing(); // "[Alfred] Sub-class's 'extraThing'"
sub.reportThing(); // "[Alfred] Base-class's 'reportThing'"
But, there's (at least!) two issues:
I'm not convinced the prototype chain is intact. If I substitute a method in the prototype via one instance of a sub-class, other instances don't see it:
No encapsulation of .name property
I'm replacing the prototype's implementation of a function like this:
Object.getPrototypeOf(oneInstance).reportThing = function() { ... }
otherInstance.reportThing() // Original version is still called
That's perhaps not a significant problem, but it is causing me to doubt my understanding.
Private variables is something I want to implement efficiently though. The module pattern of variable hiding doesn't help here, as it causes function definitions to exist per-object. I'm probably missing a way of combining patterns, so is there a way of achieving private variables without duplicating functions?
This is usually how I tackle inheritance and encapsulation in JavaScript. The defclass function is used to create a new class that doesn't inherit from any other class and the extend function is used to create a new class which extends another class:
var base = new BaseClass("Bert");
base.doThing(); // "Bert BaseClass doThing"
base.reportThing(); // "Bert BaseClass reportThing"
var sub = new SubClass("Alfred");
sub.doThing(); // "Alfred SubClass replacement doThing"
sub.extraThing(); // "Alfred SubClass extraThing"
sub.reportThing(); // "Alfred BaseClass reportThing"
var other = new SubClass("Fred");
SubClass.prototype.reportThing = function () {
console.log(this.name + " SubClass replacement reportThing");
};
other.reportThing(); // Fred SubClass replacement reportThing
<script>
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
function extend(constructor, keys) {
var prototype = Object.create(constructor.prototype);
for (var key in keys) prototype[key] = keys[key];
return defclass(prototype);
}
var BaseClass = defclass({
constructor: function (name) {
this.name = name;
},
doThing: function () {
console.log(this.name + " BaseClass doThing");
},
reportThing: function () {
console.log(this.name + " BaseClass reportThing");
}
});
var SubClass = extend(BaseClass, {
constructor: function (name) {
BaseClass.call(this, name);
},
doThing: function () {
console.log(this.name + " SubClass replacement doThing");
},
extraThing: function () {
console.log(this.name + " SubClass extraThing");
}
});
</script>
Read the following answer to understand how inheritance works in JavaScript:
What are the downsides of defining functions on prototype this way?
It explains the difference between prototypes and constructors. In addition, it also shows how prototypes and classes are isomorphic and how to create “classes” in JavaScript.
Hope that helps.
The simple recipe follows:
function BaseClass(someParams)
{
// Setup the public properties, e.g.
this.name = someParams.name;
}
BaseClass.prototype.someMethod = function(){
// Do something with the public properties
}
Now the inheritance occurs this way
function SubClass(someParams)
{
// Reuse the base class constructor
BaseClass.call(this, someParams);
// Keep initializing stuff that wasn't initialized by the base class
this.anotherProperty= someParams.anotherProperty;
}
// Copy the prototype from the BaseClass
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
// Start extending or overriding stuff
SubClass.prototype.someMethod = function(){
// In case you still wanna have the side effects of the original method
// This is opt-in code so it depends on your scenario.
BaseClass.prototype.someMethod.apply(this, arguments);
// Override the method here
}
Taken from:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
P.S. Object.create may not be supported on all old browsers, but don't worry, there's a polyfill for that in this link. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
If you want to preserve the prototype chain, you must override and use .prototype:
Example:
Main Class:
function BaseClass(){
}
BaseClass.prototype.doThing = function(){...}
SubClass:
function SubClass(){
}
SubClass.prototype= new BaseClass();
SubClass.prototype.extraThing = function(){};
Now, whenever you change extraThing or doThing it gets replaced everywhere.
The name property is accessible as a public variable (it's not static).
If you want it static, you must put it in prototype.
If you want it private, you mast make it function local:
function BaseClass(nameParam){
var name = nameParam;
}
To create an object simply call the function:
var testObj = new BaseClass("test");
testObj.doThing();
If you want to combine private variables with rewritable functions, you might find your answer here. But if you are able to rewrite the function that has access to the private variable, it's not really a private variable anymore.
I found different ways that seem to work.
Mostly recommended way in textbooks and the internet:
var Person = function() {
this.age = 23;
}
Tony = new Person();
This also seems to work:
function Person() {
this.age = 23;
}
Tony = new Person();
Is there a difference? And an additional question: Usually you cannot simply leave out parentheses. Here it is possible (new Person instead of new Person()). This is because of using the new keyword, right?
A third odd way that I just tried out looks like this:
function Person() {
return {age: 2};
}
Tony = new Person();
Tony = Person(); // both ways work! It seems that you can leave out 'new' here.
Here I don't get an object with the name of my class, but my property is also accessible and it seems like it was quite similar to both above approaches.
What shall I use and what are the technical differences? Thank you!
JavaScript is a classless language. Classes don't exist, but objects may inherit properties from each other by using prototypes. This means you are not limited to implementing inheritance in a class-like manner. Personally, I like to use a BackboneJS-inspired method (code requires UnderscoreJS):
var BaseObject = function(){}; //Create a function so that we may use the new operator.
//There may be code in the constructor
BaseObject.extend = function(obj) { //Add a static function to the BaseObject to extend it
var base = this; //Save a reference for later
//Create the constructor for the sub object. We need to extend it, so we can't use the base constructor. AFAIK, this is the only way to clone the base constructor, i.e. by creating a new function that calls it
var SubObject = _.extend(function(){
base.apply(this, arguments); //Call base constructor
}, this);
SubObject.prototype= _.extend({}, this.prototype, obj); //Create new prototype that extends the super prototype, but does not overwrite it.
return SubObject; //Return the new constructor + prototype
};
This allows you to do cool class-like stuff like this:
var Car = BaseObject.extend({
speed: 0,
acceleration: 5,
accelerate: function(){
this.speed += this.acceleration;
}
});
var RaceCar = Car.extend({
acceleration: 10,
});
var car = new Car();
var raceCar = new RaceCar();
car.accelerate();
raceCar.accelerate();
if(raceCar.speed > car.speed){
console.log('raceCar won');
}else{
console.log('car won');
}
For more information on inheritance in JavaScript, I strongly recommend reading JavaScript: The Good Parts by Douglas Crockford.
Regarding your examples:
The difference between 1 and 2 is minimal. For more information see this question.
In 3, you are just returning an object literal. The new keyword only has influence on the this keyword within the function, which you are not using, and so using new has no effect. For more information, see this quesion
1 and 2 (var x = function vs function x) are very similar. 3 is a completely different thing.
The difference between 1 and 2 has nothing to do with classes and has been asked before on SO (several times). I think the most complete answer is this one:
https://stackoverflow.com/a/338053/1669279
In short, the first x points to an anonymous function and some debugging tools might have problems with that. The first one is available from the line it was defined on while the second is available in the entire scope. Read the linked answer for details.
The 3rd "solution" is not a class at all. It is simply a function that returns an object (might be called a Factory method).
It is not a good idea to return things from your constructors, especially return this. You should only return things if you want to override the normal process of creating objects (like implementing the singleton pattern for example).
As a side-note, you should always use new when you instantiate a class. Here is what happens when you try to be smart and save characters:
function X () {
return this;
}
console.log(X()); // outputs the window object
The parenthesis after calling the constructor with no parameters are optional, but it is frowned upon to avoid them because it results in slightly more confusing code.
To sum it up, i usually use pattern 1. Pattern 2 is also ok.
One problem with pattern 2 can be this one:
var x = new X(); // works
console.log(x.message); // works, I am X
x.method(); // doesn't work, method hasn't been defined yet
function X() {
this.message = 'I am X';
}
X.prototype.method = function() {
console.log(this.message);
};
this is how i do mine:
;(function (window) {
"use strict";
//-- Private Vars
var opt, obj, rm, Debug;
//-- construtor
function App(requestedMethod) {
//-- set up some vars
if(typeof requestedMethod !== 'undefined') {
rm = requestedMethod;
}
opt = {
rMethod: (typeof rm !== 'undefined') ? (rm != null) ? rm : false : false
}
//-- containe resulable objects
obj = {}
//-- call the init method
this.init();
}
/** Public Methods **/
/**
* The Init method called on every page load
*/
App.prototype.init = function () {
var om = opt.rMethod;
//-- Once all init settings are performed call the requested method if required
if(om) {(typeof App.prototype[om] == 'function') ? App.prototype[om]() : _DB('Call to Method [' + om + '] does not exsist.');}
};
/**
* testmethod
*/
App.prototype.testmethod = function () {
};
/** Private Methods **/
function PrivateMethod(){
}
/**
* A console output that should enable to remain enable js to work in IE
* just incase i forget to remove it when checking on those pesky IE browsers....
*/
function _DB(msg){
if(window.console && window.console.log){
var logDate = new Date();
window.console.log('------------------- ' + logDate + ' ----------------------------------');
window.console.log(msg);
}
};
window.App = App;
})(window);
then call it like:
<script src="ptha/to/your/app.js"></script>
<script>$(function() { new App('testmethod'); });</script>
When the code is loaded the new App() will then run once all page load data has completed
Hope this helps.To get access to it outside add the new to a var
var App = new App('testmethod);
then you can access things like
App.testmethod()...
var Person = function() {
this.age = 23;
}
Person is a variable that contains(is referenced) an anonymous function
function Person() {
this.age = 23;
}
but here you declare a function called "Person"
function Person() {
return {age: 2};
}
and so you declare a function that returns a new static object.
The best way depends on the needs, if you want to declare classes use the second, while to create the modules uses the third. For the first method look here: http://helephant.com/2008/08/23/javascript-anonymous-functions/
Basically I want inheritable functions as in
Base = function() { };
Base.prototype.foo = function() {
console.log("base foo");
};
Derived = function() { };
somelib.inherit(Derived, Base);
Derived.prototype.foo = function() {
console.log("derived foo");
}
d = new Derived():
d.foo();
And I want it to print
derived foo
base foo
Yes I know I can explicitly call Base.prototype.foo.call(this); I'm just wondering if there is a pattern for calling overridden super class functions automatically. The problem I'm trying to solve is 2 fold.
derived classes should NOT have to remember to call their parent's method, it just happens automatically.
if 1. can't happen then at least I'd like Derived not to call Base by name since that's brittle. Rather I'd like it call parentclass or something so you don't have to know the base. That way if you change the name of the base you don't have to go fixing every derived class.
You can implement such functionality by using a structure like:
function Base(){}
Base.prototype.destroy = function(){console.log('Base destroy');};
function Derived(){}
Derived.prototype = new Base; // Let Derived inherit from Base
// Override the `destroy` method
Derived.prototype.destroy = function() {
console.log('Derived destroy');
// Call parent class method
this.constructor.prototype.destroy();
// If the context of the method is important, you can use Function.call:
//this.constructor.prototype.destroy.call(this);
};
// Create an instance of Derived, and call the destroy method:
(new Derived).destroy();
I would suggest thinking about exactly why you are doing this, at least in terms of requirement #1. Keep in mind that your desired pattern would take away a great deal of flexibility. For instance, if you have a situation where you want to print the statements in the opposite order:
base foo
derived foo
You would either have to abandon your pattern or create a function foo2() in the derived class which then calls foo() in the base class. Neither is very pretty.
Same goes if you even want to do something as simple as:
derived foo
base foo
one more thing in the derived function
I would contend that using this pattern may work for the exact thing you want to do right now, but may give you fits when you want to make a seemingly trivial change down the road. All to save one line of code!
As far as I know there is no language integrated destructor functionality in JavaScript. It is all about frameworks. If you are using ASP.NET Ajax, for example, the framework would expect that your objects would have a dispose method, responsible for freeing up resources (event handlers). So, it is up to you.
Ok, this isn't quite what you are looking for, in that it's not a "pattern", but it is a potential implementation path you could follow:
Take a look # the MooTools Class.Extras package (for lack of a better word). Using the Chain Class, you could probably get the desired functionality.
var parent = (function () {
var construct = function () {
};
construct.prototype = {
constructor: construct,
destroy: function () {
console.log('parent destruction');
}
}
return construct;
})();
var child = (function (parent) {
var construct = function () {
};
construct.prototype = Object.create(parent.prototype);
construct.prototype.constructor = construct;
construct.prototype.destroy = function () {
parent.prototype.destroy.call(this); // calling parent, too
console.log('child destruction');
};
return construct;
})(parent);
child_instance = new child();
child_instance.destroy();
I would prefer a way where I don't assign Derived = chainify() so that the api would be the same as you had in your question but as of right now this is the best way I can get it to work. It works by replacing each method of the object with a method that calls the replaced method and travels up the parent chain calling their methods along the way.
function chainify() {
return function () {
var property;
for (property in this) {
if (typeof this[property] === "function") {
this[property] = chain(this[property], property);
}
}
function chain(method, method_name) {
return function() {
method();
var current = this;
while (current = current.parent) {
if (current.hasOwnProperty(method_name)) {
current[method_name].apply(this, arguments);
}
}
};
}
}
}
var somelib = function() { };
somelib.inherit = function (derive, base) {
derive.prototype = new base;
derive.prototype.parent = base.prototype;
};
var Base = function() { };
Base.prototype.foo = function() {
console.log("base foo");
};
var Derived = chainify();
somelib.inherit(Derived, Base);
Derived.prototype.foo = function() {
console.log("derived foo");
};
d = new Derived();
d.foo();
I have this piece of code:
var Human=function(name){
this._name=name;
};
Human.prototype.Shout=function(){
alert(this._name);
};
var tom=new Human("tom");
var john=new Human("john");
alert(tom.Shout===john.Shout);
Right now ._name is not "private". I want to make ._name "private", but at the same time i do not wish to create additional functions for each instance of Human (in other words tom.Shout Must be === to john.Shout) because creating additional functions for each instance is just well.. unnecessary (ok offtopic - we can debate this on another thread)
My conclusion is that what I'm trying to achieve (having ._name be "private" and at the same time having tom.Shout===john.Shout) is impossible.
But I just want to be 200% sure before jumping into any conclusions.
(I welcome any hacks as long as the requirements are met, i.e no creating of additional functions for each instance)
If we have to create additional functions to do scoping that's fine but that number should be a fixed number and that number should not increase with each additional instance of Human.
Update
Your looking for #name which is an instance variable. Pray it's in es.next, but we don't have it yet. Maybe in two years.
If you care about a clean API then here is your solution:
function Class(foo) {
Class.priv(this).foo = foo;
}
Class.priv = (function() {
var cache = [],
uid = 1;
return function(obj) {
if (!this.__id) {
this.__id = uid;
cache[uid++] = {};
}
return cache[this.__id];
};
}());
Class.prototype.bar = function() {
console.log(Class.priv(this).foo);
}
Store all the data in a cache as a function of the constructor. No data is cluttered on the object.
Original
However there is no such thing as "private".
All you can do is create a local variable inside a function.
The constructor function
var Human = function(name) {
// local variable.
var _name = name;
}
Has a local variable that by very definition of being local is not usable outside of the constructor function.
This means that you cannot access it in external code like the prototype.
What you can do however is make it read only using ES5
var Human = function(name) {
Object.defineProperty(this, "name", { value: name });
}
If you can truly achieve what your asking, you'd make a huge breakthrough in js. I've attempted to do just that for many hours.
A different pattern would be :
var Human = function(name) {
this.name = name;
return {
Shout: this.Shout.bind(this)
};
}
Human.prototype.Shout = function() {
console.log(this.name);
}
This has the overhead of calling .bind and creating a new object for every instance though.
how about this ?
var Human = function (name) {
var _name = name;
this.getName = function () {
return _name;
}
};
Human.prototype.Shout = function () {
alert(this.getName());
};
var tom = new Human("tom");
var john = new Human("john");
tom.Shout(); // tom
john.Shout(); // john
alert(tom.Shout === john.Shout); // true
EDIT:
the former creates another function for GET property,
it is not possible without creating additional functions.
Did read the question, didn't understand, because this._name is just not private, so the question is a bit weird. This is how in my test the prototype methods are added once and available to all instances. I repeat: this._name is not private here. If you add a local variable, and want to access it via a closure in a prototype method, calling the value of the local variable will result in the same value for all instances.
Anyway, with this constructor function the this._name getter and shout methods are added to the prototype chain once and thereby available for all instances of Human.
function Human(name) {
if (!(this instanceof Human)){
return new Human(name);
}
this._name = name;
if (!Human.prototype.Name){
Human.prototype.Name = function(val){
if (val){
this._name = val;
return this;
}
return this._name;
};
Human.prototype.shout = function(){
alert(this._name);
}
}
}
i'm quite a newbie in javascript, and i'm spending some time trying to create namespaced objects in js.
Now, that's what i'm trying to do:
MainObject = function() {
var privateVariable = "i'm private";
var privateMethod = function() {
// doSomething
}
this.publicMethod = function() {
// doPublicSomething
}
}
MainObject.prototype.nested = function() {
this.publicNestedMethod = function() {
// that's not working at all
this.privateMethod(privateVariable);
}
}
MyObject = new MainObject();
MyObject.publicMethod();
MyObject.publicNestedMethod();
I tried to include the nested class inside the first one, but it's not working also if i try:
this.nested = function() {
var mainObject = this;
return {
publicNestedMethod = function() {
mainObject.privateMethod();
}
}
}();
Someone can help me please? i'm gonna loose my mind on this.
Phaedra.
Closures are a lexical feature, not a semantic one. If the object is outside the lexical scope of another, it can no longer be "nested" and access the former's local variables. In the code of your nested function/class, there's no such thing as this.privateMethod, because privateMethod is never made to be a property of MainObject. It's simply a local variable inside a function.
There's no such things as "private properties", "private methods" or "private members" in JavaScript. Hell, there's no such thing as a "class". Some people like to emulate private members using local variables as above, but doing so results in cases like this, where the discrepancy between the two concepts comes and bites one in the behind.
To conclude, it is a bad idea to write Java code, with all its OO techniques in JS, just as it is a bad idea to write C code, with all its pointers and unbounded buffers, in C#. Sure, in both cases you can do it, but you would be failing to appreciate and exploit the language's features this way.
And now that I'm done with the rant, you can do something like this to get "namespaced" functions:
MainObject = function() {
var privateVariable = "I'm private";
var privateMethod = function() {
alert('Private');
}
this.publicMethod = function() {
alert('Public');
}
this.nested = {
publicNestedMethod: function() {
privateMethod();
}
};
// or
this.nested = (function() {
var nestedPrivate = 5;
return {
publicNestedMethod: function() {
alert(nestedPrivate);
privateMethod();
}
};
})();
}
MyObject = new MainObject();
MyObject.publicMethod();
MyObject.nested.publicNestedMethod();
Using the convention of underscore for "private" methods is a reasonable way to keep things organized.
MainObject = function() {
this._privateVariable = "i'm private";
this._privateMethod = function() {
// doSomething
}
this.publicMethod = function() {
// doPublicSomething
}
}
Well to provide the benefit of prototypal inheritance where all "subclasses" share a single instance of the method in prototype, but to ALSO provide the feature of inheriting private instances...
I came up with:
function Person(name,latentPower){
var privatesForChildren = { password:"xyz"
,latentPower:"invisibility"}
this.inherit = function(){
for(v in privatesForChildren){
eval("var " + v + "=privatesForChildren['" + v + "'];");
}
}
this.name = name;
this.revealName = function(){ alert("My name is" + this.name + "."); }
this.revealPowers = function(){ alert("I'm normal."); }
}
function Mutant(name,latentPower,fuel){
this.inherit.call(this); // Inherit private instance variables
var fuel = fuel;
this.name = name;
this.revealPowers = function(){
alert("I manifest the powers of " + latentPower + " when I " + fuel + ".");
}
}
Mutant.prototype = new Person;
Mutant.prototype.constructor = Mutant;
bob = new Person("Bob","telekenesis");
jim = new Mutant("Jim","nausea","eat pizza");
buford = new Mutant("Buford","Teflon Man","breathe");
jim.revealName(); //Inherited properly from prototype
bob.revealPowers();
jim.revealPowers();
buford.revealPowers(); //distinct from Jim's so is an "instance var"
alert(bob.latentPower); //returns undefined
alert(buford.latentPower); //returns undefined, so is "private".
How useful is that?
JavaScript Classes and Inheritance (ES6)
According to ES6, you can use JavaScript classes and inheritance to accomplish what you need.
JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance.
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
I'm showing the examples below with variables, but it can be applied also to functions.
Inheritance (1st Approach)
This solution can only be used with getters for your private variables, otherwise your subclass will not get access to them.
class Main {
constructor() {
let privateVariable = "private";
this.publicVariable = "public";
this.getPrivateVariable = () => {
return privateVariable;
}
}
}
Main.Sub = class Sub extends Main {
getAllVariables() {
return this.publicVariable + "-" + this.getPrivateVariable();
}
}
// Testing...
let main = new Main();
let sub = new Main.Sub();
console.log(main.privateVariable); // undefined
console.log(main.publicVariable); // "public"
console.log(sub.privateVariable); // undefined
console.log(sub.publicVariable); // "public"
console.log(main.getPrivateVariable()); // "private"
console.log(sub.getPrivateVariable()); // "private"
console.log(sub.getAllVariables()) // "public-private"
Nesting (2nd Approach)
Maybe this solution is better for you because it doesn't expose your private variables outside the Main and Nested classes.
class Main {
constructor() {
let privateVariable = "private";
this.publicVariable = "public";
Main.Nested = class Nested extends Main {
getAllVariables() {
return this.publicVariable + "-" + privateVariable;
}
}
}
}
// Testing...
let main = new Main();
let nested = new Main.Nested();
console.log(main.privateVariable); // undefined
console.log(main.publicVariable); // "public"
console.log(nested.privateVariable); // undefined
console.log(nested.publicVariable); // "public"
console.log(main.getPrivateVariable); // undefined
console.log(nested.getPrivateVariable); // undefined
console.log(nested.getAllVariables()) // "public-private"
What OO system lets you inherit private methods? Part of being private is being unaccessible from other objects.
In JS in particular, "private members" are really just local variables of the function where they are declared. JS doesn't have typical OO notions of "class", "inheritance", "public", and "private", so you can't expect to copy your OOP techniques verbatim from other OOP languages.
It is a convention. You can imitate OO Java techniques like private members but that's not recommended. You can imitate in this way:
MyFunction = function(options){
var private = {};
//to reference MyFunction as a context
var that = this;
function privateFunctionThatCallPublicMethod(){
that.publicFunction("hello");
}
this.publicFunction = function(params){
alert(params + " " + private);
}
...
}
var instance = new MyFunction({oneOption:'fsdfsad'});
This is the bests approach i found to emulate OO Java Techniques...
But there is a problem, is very inefficient...
You must use prototype instead, because otherwise it would create one object per function per instance of the "class".
MyFunction = function(options){
this._private = {};
}
MyFunction.prototype._privateFunctionThatCallPublicMethod = function(){
this.publicFunction("hello");
}
MyFunction.prototype.publicFunction = function(params){
alert(params + " " + this._private);
}
Like you think private members are (in this way) a convention.
Also, there is another thing you must know...
When you pass a function of an object as a parameter to another function you must bind the context of the function...
function bind(fnThis, fn) {
return function(){
return fn.apply(fnThis, arguments);
};
}
function makeSomething(callback){
callback("hello");
}
var instance = new MyFunction();
makeSomething(bind(instance, instance.publicFunction));
This is because you must bind "this" as instance in the body of the publicFunction, otherwise is gonna be "window" instead.