Javascript inheritance and encapsulation, done efficiently - javascript

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.

Related

calling prototype methods from javascript constructor

I have the following simple inheritence pattern and I would like to know if it's ok to call methods the way i do from within the constructor function (basically speaking, using this instead of "super prototype".
Parent class, Pet
function Pet(name) {
this.name = name;
this.nickname = name;
this.adopt();
}
Pet.prototype.adopt = function() {
this.nickname = 'Cutty ' + this.name;
}
Pet.prototype.release = function() {
this.nickname = null;
}
Pet.prototype.cuddle = function() {
console.log(this.name + ' is happy');
}
Subclass, Lion
function Lion(name) {
Pet.prototype.constructor.apply(this, arguments); // super(name)
this.cuddle();
this.release();
}
Lion.inherits(Pet);
Lion.prototype.adopt = function() {
// DTTAH
}
Lion.prototype.release = function() {
Pet.prototype.release.call(this);
console.log('Thanks for releasing ' + this.name);
}
inherits helper (polyfills are bad I know)
Function.prototype.inherits = function(Parent) {
function ProtoCopy() {}
ProtoCopy.prototype = Parent.prototype;
this.prototype = new ProtoCopy();
this.prototype.constructor = this;
}
My pets are instantiated like so var lion = new Lion('Simba')
In Lion constructor,
Can I keep using this when calling sub/parent class methods ? Or should I use methods from parent prototype directly ? (like pseudo call to super() or in release())
Reasons why I am asking are:
this substitution at runtime
constructor property not always what we are thinking (from what I read here and there)
I am not sure how these things can influence the resulting object.
Thanks for your enlightenment !
What is the difference between using this.fn() and MyClass.prototype.fn.call(this) in a constructor function?
This is not specific to constructor functions, it's the same in all functions (methods) that are called on instances.
Indeed there's not much difference apart from the character count when this.fn === MyClass.prototype.fn, and they would behave exactly the same. However, this assumption is not always true - this might not inherit from MyClass.prototype directly, but rather be a subclass instance, and that subclass might have overwritten the this.fn method.
So which one is correct? Both, in fact. If you know the difference, you can choose the appropriate one for your case. Other languages have different default expectations here, see also for calling static methods.
Notice that you cannot replace the class reference by this.constructor, which would be overwritten as well. In a reasonable setup1, this.fn() would be always equivalent to this.constructor.prototype.fn.call(this).
This is similar to the reason why super calls must explicitly reference the super class, and not depend on instance properties (such as this.constructor, this.super or anything similar).
1: Where this.fn is a usual method inherited from the prototype, not an own instance-specific one, and where every prototype has the .constructor pointing to the respective constructor whose .prototype it is.
Simplifying the problem, consider the following code in ES6:
class Pet {
constructor (name) {
this.name = name;
this.talk();
}
talk () {
console.log('My name is ' + this.name);
}
}
class Lion extends Pet {
constructor (name) {
super(name);
}
talk () {
super.talk();
console.log('I am a lion.');
}
}
would be equivalent to:
function Pet (name) {
this.name = name;
this.talk();
}
Pet.prototype.talk = function () {
console.log('My name is ' + this.name);
};
function Lion (name) {
Pet.call(this, name);
}
// inheritance:
Lion.prototype = Object.create(Pet.prototype);
Lion.prototype.constructor = Lion;
// override .talk
Lion.prototype.talk = function () {
Pet.prototype.talk.call(this);
console.log('I am a lion');
}
Running new Lion('Bobby') logs:
My name is Bobby
I am a lion
Further reading: http://eli.thegreenplace.net/2013/10/22/classical-inheritance-in-javascript-es5

How can I extend a class defined behind a closure in JavaScript?

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.

Get name of derived constructor in Javascript

Is it possible to get the name of the derived "class" in the following example? I'd like to somehow have the output be "ChildClass", but instead it's "ParentClass".
function ParentClass() { this.name = 'Bob' }
function ChildClass() { this.name = 'Fred' }
ChildClass.prototype = Object.create(ParentClass.prototype);
var child_instance = new ChildClass()
console.log('ChildClass type:', child_instance.constructor.name)
I realize I can do this.my_type = 'ChildClass' in the ChildClass constructor, but I have many classes that extend ParentClass and doing this everywhere would be inconvenient.
The problem in your case is that you're overwriting the prototype property of ChildClass but you're not reseting the constructor property on the new prototype. You need to add one extra line:
function ParentClass() {
this.name = "Bob";
}
function ChildClass() {
this.name = "Fred";
}
ChildClass.prototype = Object.create(ParentClass.prototype);
ChildClass.prototype.constructor = ChildClass; // add this line to your code
Now your code will work as expected. The following answer explains why your original code didn't work: https://stackoverflow.com/a/8096017/783743
Personally I don't like writing "classes" like this with the constructor and the prototype dangling separately. It's just too tedious to type, incoherent, a pain on the eyes and difficult to maintain. Hence I use the following utility function to create classes:
function defclass(base, body) {
var uber = base.prototype;
var prototype = Object.create(uber);
var constructor = (body.call(prototype, uber), prototype.constructor);
constructor.prototype = prototype;
return constructor;
}
Now you can create classes as follows:
var ParentClass = defclass(Object, function () {
this.constructor = function () {
this.name = "Bob";
};
});
var ChildClass = defclass(ParentClass, function () {
this.constructor = function () {
this.name = "Fred";
};
});
This method has several advantages:
Inheritance and class definition have been combined into one.
The constructor is just another prototype method.
Everything is nicely encapsulated within a single closure.
Calling base class prototype methods is easy.
You can create private static functions easily.
Hope that helps.

How to achieve pseudo-classical inheritance right on the class declaration? [duplicate]

This question already has answers here:
How to implement C# access modifiers in javascript?
(5 answers)
Closed 1 year ago.
Note:
As the answers tell, the code proposed in the question does NOT really achieve inheritance(otherwise it becomes an answer rather than a question .. ) due to some issues described in the question and in my comments. It works as expected as a fake of inheritance(and not even prototypal).
Summary
In short, make it as similar as we are writing a general OO language rather than javascript, but keep the inheritance be correct.
The story
Object.create is a good way to achieve prototypal inheritance, but it's a bit confusing to a typed brain and new fans.
There are various ways that we can write javascript code more like we are writing other OO languages with the pseudo-classical pattern. As it's pseudo-classical, we must deal with the underlying prototypal inheritance of javascript correctly.
What I want to find is an approach that the pseudo-classical inheritance can be achieved right on the class declaration. The code for demonstration is put at the rear of the post, it works as expected, however, there are some annoying things:
I cannot get rid of return in the class declaration or the inheritance won't work.
I have no way except pass this in the class declaration to make the returning closure know what is this.
I also want to get rid of function (instance, _super) {, but not yet have a good idea.
The static(own properties) of a class are not inherited.
A solution would be more of some syntactic sugar than the existing frameworks, a good pattern is applicable.
The _extends function:
function _extends(baseType) {
return function (definition) {
var caller=arguments.callee.caller;
var instance=this;
if(!(instance instanceof baseType)) {
(caller.prototype=new baseType()).constructor=caller;
instance=new caller();
}
var _super=function () {
baseType.apply(instance, arguments);
};
definition(instance, _super);
return instance;
};
}
The Abc class:
function Abc(key, value) {
return _extends(Object).call(this, function (instance, _super) {
instance.What=function () {
alert('What');
};
instance.getValue=function () {
return 333+Number(value);
};
instance.Value=instance.getValue();
instance.Key=key;
});
}
The Xyz class:
function Xyz(key, value) {
return _extends(Abc).call(this, function (instance, _super) {
_super(key, value);
instance.That=function () {
alert('That');
};
});
}
Example code:
var x=new Xyz('x', '123');
alert([x.Key, x.Value].join(': ')+'; isAbc: '+(x instanceof Abc));
var y=new Xyz('y', '456');
alert([y.Key, y.Value].join(': ')+'; isAbc: '+(y instanceof Abc));
var it=new Abc('it', '789');
alert([it.Key, it.Value].join(': ')+'; isAbc: '+(it instanceof Abc));
alert([it.Key, it.Value].join(': ')+'; isXyz: '+(it instanceof Xyz));
x.What();
y.That();
it.What();
it.That(); // will throw; it is not Xyz and does not have That method
No. No. No. This won't do. You're doing inheritance in JavaScript all wrong. Your code gives me migraines.
Creating a Pseudo-Classical Inheritance Pattern in JavaScript
If you want something similar to classes in JavaScript then there are a lot of libraries out there which provide it to you. For example using augment you could restructure your code as follows:
var augment = require("augment");
var ABC = augment(Object, function () {
this.constructor = function (key, value) {
this.key = key;
this.value = value;
};
this.what = function () {
alert("what");
};
});
var XYZ = augment(ABC, function (base) {
this.constructor = function (key, value) {
base.constructor.call(this, key, value);
};
this.that = function () {
alert("that");
};
});
I don't know about you but to me this looks a lot like classical inheritance in C++ or Java. If this solves your problem, great! If is doesn't then continue reading.
Prototype-Class Isomorphism
In a lot of ways prototypes are similar to classes. In fact prototypes and classes are so similar that we can use prototypes to model classes. First let's take a look at how prototypal inheritance really works:
The above picture was taken from the following answer. I suggest you read it carefully. The diagram shows us:
Every constructor has a property called prototype which points to the prototype object of the constructor function.
Every prototype has a property called constructor which points to the constructor function of the prototype object.
We create an instance from a constructor function. However the instance actually inherits from the prototype, not the constructor.
This is very useful information. Traditionally we've always created a constructor function first and then we've set its prototype properties. However this information shows us that we may create a prototype object first and then define the constructor property on it instead.
For example, traditionally we may write:
function ABC(key, value) {
this.key = key;
this.value = value;
}
ABC.prototype.what = function() {
alert("what");
};
However using our newfound knowledge we may write the same thing as:
var ABC = CLASS({
constructor: function (key, value) {
this.key = key;
this.value = value;
},
what: function () {
alert("what");
}
});
function CLASS(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
As you can see encapsulation is easy to achieve in JavaScript. All you need to do is think sideways. Inheritance however is a different issue. You need to do a little more work to achieve inheritance.
Inheritance and Super
Take a look at how augment achieves inheritance:
function augment(body) {
var base = typeof this === "function" ? this.prototype : this;
var prototype = Object.create(base);
body.apply(prototype, arrayFrom(arguments, 1).concat(base));
if (!ownPropertyOf(prototype, "constructor")) return prototype;
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
Notice that the last three lines are the same as that of CLASS from the previous section:
function CLASS(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
This tells us that once we have a prototype object all we need to do is get its constructor property and return it.
The first three lines of augment are used to:
Get the base class prototype.
Create a derived class prototype using Object.create.
Populate the derived class prototype with the specified properties.
That's all that there is to inheritance in JavaScript. If you want to create your own classical inheritance pattern then you should be thinking along the same lines.
Embracing True Prototypal Inheritance
Every JavaScript programmer worth their salt will tell you that prototypal inheritance is better than classical inheritance. Nevertheless newbies who come from a language with classical inheritance always try to implement classical inheritance on top of prototypal inheritance, and they usually fail.
They fail not because it's not possible to implement classical inheritance on top of prototypal inheritance but because to implement classical inheritance on top of prototypal inheritance you first need to understand how true prototypal inheritance works.
However once you understand true prototypal inheritance you'll never want to go back to classical inheritance. I too tried to implement classical inheritance on top of prototypal inheritance as a newbie. Now that I understand how true prototypal inheritance works however I write code like this:
function extend(self, body) {
var base = typeof self === "function" ? self.prototype : self;
var prototype = Object.create(base, {new: {value: create}});
return body.call(prototype, base), prototype;
function create() {
var self = Object.create(prototype);
return prototype.hasOwnProperty("constructor") &&
prototype.constructor.apply(self, arguments), self;
}
}
The above extend function is very similar to augment. However instead of returning the constructor function it returns the prototype object. This is actually a very neat trick which allows static properties to be inherited. You can create a class using extend as follows:
var Abc = extend(Object, function () {
this.constructor = function (key, value) {
this.value = 333 + Number(value);
this.key = key;
};
this.what = function () {
alert("what");
};
});
Inheritance is just as simple:
var Xyz = extend(Abc, function (base) {
this.constructor = function (key, value) {
base.constructor.call(this, key, value);
};
this.that = function () {
alert("that");
};
});
Remember however that extend does not return the constructor function. It returns the prototype object. This means that you can't use the new keyword to create an instance of the class. Instead you need to use new as a method, as follows:
var x = Xyz.new("x", "123");
var y = Xyz.new("y", "456");
var it = Abc.new("it", "789");
This is actually a good thing. The new keyword is considered harmful and I strongly recommend you to stop using it. For example it's not possible to use apply with the new keyword. However it is possible to use apply with the new method as follows:
var it = Abc.new.apply(null, ["it", "789"]);
Since Abc and Xyz are not constructor functions we can't use instanceof to test whether an object is an instance of Abc or Xyz. However that's not a problem because JavaScript has a method called isPrototypeOf which tests whether an object is a prototype of another object:
alert(x.key + ": " + x.value + "; isAbc: " + Abc.isPrototypeOf(x));
alert(y.key + ": " + y.value + "; isAbc: " + Abc.isPrototypeOf(y));
alert(it.key + ": " + it.value + "; isAbc: " + Abc.isPrototypeOf(it));
alert(it.key + ": " + it.value + "; isXyz: " + Xyz.isPrototypeOf(it));
In fact isPrototypeOf is more powerful than instanceof because it allows us to test whether one class extends another class:
alert(Abc.isPrototypeOf(Xyz)); // true
Besides this minor change everything else works just like it did before:
x.what();
y.that();
it.what();
it.that(); // will throw; it is not Xyz and does not have that method
See the demo for yourself: http://jsfiddle.net/Jee96/
What else does true prototypal inheritance offer? One of the biggest advantages of true prototypal inheritance is that there's no distinction between normal properties and static properties allowing you to write code like this:
var Xyz = extend(Abc, function (base) {
this.empty = this.new();
this.constructor = function (key, value) {
base.constructor.call(this, key, value);
};
this.that = function () {
alert("that");
};
});
Notice that we can create instances of the class from within the class itself by calling this.new. If this.constructor is not yet defined then it returns a new uninitialized instance. Otherwise it returns a new initialized instance.
In addition because Xyz is the prototype object we can access Xyz.empty directly (i.e. empty is a static property of Xyz). This also means that static properties are automatically inherited and are no different from normal properties.
Finally, because the class is accessible from within the class definition as this, you can created nested classes which inherit from the class which they are nested within by using extend as follows:
var ClassA = extend(Object, function () {
var ClassB = extend(this, function () {
// class definition
});
// rest of the class definition
alert(this.isPrototypeOf(ClassB)); // true
});
See the demo for yourself: http://jsfiddle.net/Jee96/1/
There's an exhaustive tutorial on how to do what you're after.
oop-concepts
pseudo-classical-pattern
all-one-constructor-pattern
I know this doesn't answer your question because as far as I know there is no good way to put everything in the function constructor and have it use prototype.
As I've commented; if you have trouble with the JavaScript syntax then typescript could be a good alternative.
Here is a helper function that I use for inheritance and overriding (calling super) using JavaScript (without Object.create)
var goog={};//inherits from closure library base
//http://docs.closure-library.googlecode.com/git/closure_goog_base.js.source.html#line1466
// with modifications for _super
goog.inherits = function(childCtor, parentCtor) {
function tempCtor() {};
tempCtor.prototype = parentCtor.prototype;
childCtor.prototype = new tempCtor();
childCtor.prototype.constructor = childCtor;
// modified _super
childCtor.prototype._super = parentCtor.prototype;
};
// Parent class dev
var Parent = function(){};
Parent.prototype.sayHi=function(){
console.log("hi from Parent");
}
// end class
// Child class dev
var Child = function(){}
goog.inherits(Child,Parent);
Child.prototype.sayHi=function(){
//_super only works on parent.prototype
//this is where functions are usually defined
//have to add this. to call _super as well
this._super.sayHi();
console.log("hi from Child");
}
// end Child
//code to test
var c = new Child();
c.sayHi();//hi from Parent and hi from Child
Even if you find a way to write helper functions and make JS constructor functions look like Java classes you have to understand prototype.
You can always try jOOP, though it does require jQuery.
https://github.com/KodingSykosis/jOOP
var myClass = $.cls({
main: function() {
$('body').append('My App is loaded <br/>');
}
});
var mySecondClass = $.cls({
main: function() {
this._super();
$('body').append('My Second App is loaded <br/>');
}
}, myClass);
var app = new mySecondClass();
http://jsfiddle.net/kodingsykosis/PrQWu/
I believe you are looking for more functionality than this, but if you want to just inherit a bunch of methods from another class you could do this
http://cdpn.io/Jqhpc
var Parent = function Parent () {
this.fname = 'Bob';
this.lname = 'Jones';
};
Parent.prototype.getFname = function getFname () {
return this.fname;
};
Parent.prototype.getLname = function getLname () {
return this.lname;
};
var Child = function Child () {
this.fname = 'Jim';
};
Child.prototype = Parent.prototype;
var child = new Child();
document.write(child.getFname()); //=> Jim

Nested class in javascript, inheritance of private methods

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.

Categories