JavaScript OOP: classical implementation odd - javascript

OK, I've revised most of the techniques to implement inheritance in JavaScript OOP.
As a Java programmer, I'm interested in the classical approach but here's the problem; say I want to create the Animal class (I know it's not a real class, but let me use this term) like this:
function Animal(name){
this.name = name;
}
Animal.prototype.getName = function() {
return this.name;
}
It is important to note that this is a concrete class in my first intention, I want to instantiate it, not just use it as a superclass. I may create several Animal instances, each one with its own name.
A possible way to extend this class is to do the following:
function Cat(name, owner) {
this.name = name;
this.owner = owner;
}
// ALTERNATIVE 1:
Cat.prototype = Object.create(Animal.prototype);
// ALTERNATIVE 2:
Cat.prototype = new Animal('LOLA');
// END OF ALTERNATIVES
Cat.constructor.prototype = Cat;
Cat.prototype.jump = function() {
alert(this.name + " jumping");
}
With the ALTERNATIVE 1 we just inherit the methods of the superclass, in fact we need to redefine the name property in the Cat. With the ALTERNATIVE 2 nothing actually changes, we just have one more object in the chain that holds a name property that's quite useless: it's the same for all the Cat instances.
The point here is that I've written the Animal class with its own name and I just throw it away as soon as I extend it. What I'd like to have though is a way to inherit both properties and methods and, most of all, I'd like to be able to reuse the Animal constructor.

The traditional way to inherit the properties of the base constructor is as follows:
function Cat(name, owner) {
Animal.call(this, name); // call the base constructor
this.owner = owner;
}
Cat.prototype = new Animal;
Cat.prototype.constructor = Cat;
Cat.prototype.jump = function () {
alert(this.name + " jumping");
};
The above code is equivalent to the following class in other languages:
class Cat extends Animal {
constructor(name, owner) {
super(name);
this.owner = owner;
}
jump() {
alert(this.name + " jumping");
}
}
The new way to inherit properties is exactly the same, save that we replace new Animal with Object.create(Animal.prototype). The reason we prefer the new way is because:
Calling new Animal is unnecessary overhead. The Cat constructor calls it again anyway.
Calling new Animal might not return a blank object. It might add some properties to the object.
We don't know what arguments to call new Animal with yet. Hence it makes no sense to call it.
Thus the preferred way of inheritance is now:
function Cat(name, owner) {
Animal.call(this, name); // call the base constructor
this.owner = owner;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.jump = function () {
alert(this.name + " jumping");
};
Note that it's important to call the base constructor because it may do some initialization which is necessary for the instance to work properly.
If you're interested in writing JavaScript code in a classical style then take a look at the following answer which describes prototype-class isomorphism. The following code it taken from the above answer:
function CLASS(prototype, base) {
switch (typeof base) {
case "function": base = base.prototype;
case "object": prototype = Object.create(base, descriptorOf(prototype));
}
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
function descriptorOf(object) {
return Object.keys(object).reduce(function (descriptor, key) {
descriptor[key] = Object.getOwnPropertyDescriptor(object, key);
return descriptor;
}, {});
}
Using the CLASS function we can define pseudo-classes in JavaScript as follows:
var Animal = CLASS({
constructor: function (name) {
this.name = name;
},
getName: function () {
return this.name;
}
});
var Cat = CLASS({
constructor: function (name, owner) {
Animal.call(this, name);
this.owner = owner;
},
jump: function () {
alert(this.name + " jumping");
}
}, Animal);
There are other ways to do inheritance in JavaScript as well. I suggest you read my blog post on Why Prototypal Inheritance Matters to understand more about inheritance in JavaScript.

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

Javascript inheritance and encapsulation, done efficiently

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.

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 use prototype to avoid copying of functions in javascript?

I had written this code to simulate OOP inheritance and calling baseclass in javascript and it works:
function Animal(name,age)
{
this._name = name;
this.setName = function (name) { this._name = name }
this.getName = function() { return this._name }
}
function Cat(name,age)
{
Animal.call(this,name,age); // call baseclass constructor
this.getName = function() { return Cat.prototype.getName.call(this)+", a cat" }
}
Cat.prototype = new Animal(); // will create the baseclass structure
/// ***** actual execution *****
var puss = new Cat("Puss",3);
var cheshire = new Cat("Cheshire",10);
// do some actions
console.log ( puss.getName() );
// change cat's name
puss.setName("Puss in boots");
alert ( "new name -->"+puss.getName() );
problem is that, for each instance of "new Cat()" the "getName" and "setName" functions are replicated.
I have read a lot of articles on prototyping but none addressed the issue of calling the baseclass function.
You should assign the methods to the prototype of the function, for example,
function Animal(name, age) {
this._name = name;
this._age = age;
}
Animal.prototype.getName = function () { return this._name; }
Animal.prototype.setName = function (value) { this._name = value; }
function Cat(name, age) {
Animal.call(this, name, age);
}
Cat.prototype = new Animal();
Cat.prototype.getName = function () {
return Animal.prototype.getName.call(this) + ", a cat";
}
Are you looking for __proto__ which stores prototype data?
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/Proto
If you do a console.log(puss.__proto__.getName) you'll get what seems to be the "baseclass" function but I'm not sure how cross-browser is this.
From http://phrogz.net/js/classes/OOPinJS2.html
Javascript does not have any sort of 'super' property, which would
point to its parent class. Instead, you use the call() method of a
Function object, which allows you to run a function using a different
object as context for it. If you needed to pass parameters to this
function, they would go after the 'this'.
In your case it works the same for functions as "methods", so you can do:
Animal.prototype.setName.call(this, name);

JavaScript Object Inheritance - What am I doing wrong?

What is wrong with this code? Can somebody help me with JavaScript Object Inheritance? I am starting to feel like an idiot!!
Thanks in advance,
Sam
function Human(name, sex) {
this.name = name;
this.sex = sex;
};
function Man(name) {
Man.prototype = new Human(name, "Male");
};
var m = new Man("Sam Striano");
alert(m.name); //<-- = Undefined
You want this instead:
function Man(name) {
Human.call(this, name, "Male");
}
What that code does
It seems like you're only trying to call the constructor of the parent, Human, which isn't the same is prototypal inheritance. The code above takes the constructor for Human and applies it to this - a new Man object.
What your code does
The line Man.prototype = new Human(name, "Male") is changing the prototype of Man every time a new Man is created. Not only that, you're completing re-assigning the prototype object, and so it will only apply to objects created after that assignment - i.e. not the first one. Hence, m.name is undefined.
Proper prototypal inheritance
Note that calling the parent's constructor, as in my code above, won't cause Man to automatically inherit any methods assigned to Human.prototype. The best way to do this is to clone Human.prototype into Man.prototype but outside of any constructors. Like this:
function Man(name) {
Human.call(this, name, "Male");
}
function inherit(parent, child) {
if (Object.create) child.prototype = Object.create(parent.prototype);
else {
for (var key in parent.prototype) {
if (!parent.prototype.hasOwnProperty(key)) continue;
child.prototype[key] = parent.prototype[key];
}
}
}
inherit(Human, Man);
This may seem rather verbose, and the alternative may be to do this:
Man.prototype = new Human('no name', 'Male');
Which will work, but causes unwanted side-effects since we're forced to assign a dud name to the prototype, and it's letting the constructor for Human call an extra time just for assigning the prototype. Be warned if you go down this path and later change the Human constructor to do more than just assign properties to this.
There's usually two steps to mimic classical inheritance in javascript:
Your subclass constructor needs to call the parent constructor
Your subclass prototype needs to chain into the parent prototype
the first step usually looks like
function Subclass(blah) {
ParentClass.apply(this, arguments);
}
The second step is trickier. On JS environments that implement the __proto__ property, you could do
Subclass.prototype = {
__proto__ : ParentClass.prototype,
subclassMethod1: function() { /* ... */ }
}
Unless you know exactly where your script will run (like in a node.js environment), you can't rely on __proto__ being available to your script, so the general approach will require to use Crockford's object() method:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
Subclass.prototype = Object.create(ParentClass.prototype);
Subclass.prototype.subclassMethod1 = function() { /* ... */ }
That's the gist of it. ES5 runtimes may have Object.create() already built-in, and that's fine.
There are leftover things to complete the illusion of classic inheritance, such as the ability to easily call a parent class' overriden method. With what we have now, you'd need to have something like ParentClass.prototype.overridenMethod.call(this, arg1, arg2) in your Subclass method.
Some OO libraries will helpfully define extra cruft on each of your subclass instances so you can use things like this.superclass.overridenMethod(arg1, arg2).
The implementation of that cruft is left as an exercise to the reader ;)
I think what you're after is to have the Man class in inherit properties from Human. You're on the right track, but would need to apply a new Human instance once as the prototype object of Man.
function Human(name, sex) {
this.name = "some default";
this.sex = sex;
};
function Man(name) {
if( name !== undefined )
this.name = name;
};
Man.prototype = new Human(name, "Male");
Man.prototype.constructor = Man;
var m = new Man("Sam Striano");
alert(m.name); // alerts "Sam Striano"
alert(m.sex); // alerts "Male"
As far as I know, you should handle all stuff with prototype and constructor and the inerithance could be managed in this way:
// Define superclass
function Human( name, sex ) {
this.name = name;
this.sex = sex;
}
// Define superclass methods
Human.prototype.method1 = function() {
alert( 'This is the call to ORIGINAL method1() with name: ' + this.name + ' and sex: ' + this.sex );
}
// Define subclass
function Man( name, age ) {
this.constructor.apply( this, [ name, 'Man' ] );
this.age = age;
}
// Define subclass inerithance
Man.prototype = new Human();
// Define subclass methods
Man.prototype.method1 = function() {
alert( 'This is the call to OVERWRITE method1() with name: ' + this.name + ' and sex: ' + this.sex + ' and age: ' + this.age );
this.constructor.prototype.method1.apply( this );
}
var m = new Man( 'Sam Satriano', 30 );
m.method1();
// Should alert:
// This is the call to OVERWRITE method1() with name: Sam Satriano and sex: Man and age: 30
// This is the call to ORIGINAL method1() with name: Sam Satriano and sex: Man
Hope this helps. Ciao!
Without getting into an inheritance fight, your problem can be solved by changing your code to the following:
function Human(name, sex) {
this.name = name;
this.sex = sex;
};
function Man(name) {
// This is how you call the parent's constructor
Human.call(this, name, "Male");
};
// The call to setup the prototype only needs to happen once
// Not in every instantiation of the object
Man.prototype = new Human();
// Have to fix the constructor, right now it's set to Human
Man.prototype.constructor = Man;
var m = new Man("Sam Striano");
>> m.name // outputs "Sam Striano";
>> m instanceof Human // outputs true
This is still not an ideal way to inherit. I posted something explaining what makes good JS inheritance. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

Categories