Inheritance in JS: this.base = Class(); this.base() or ...? - javascript

I am trying to "get" inheritance in JS.
I just discovered a neat way to basically copy all properties from one object into another:
function Person(name){
this.name="Mr or Miss: "+name;
this.introduce = function(){
console.log("Hi, I am "+this.name);
}
}
function Employee(name,title){
this.title=title;
this.base=Person;
this.base(name);
}
e = new Employee('tony', 'manager')
e.introduce();
Note that I have a Person() class with a constructor, and its attribute "name" is generated by the constructor.
The great thing about this is also that then employee has ALSO the name in the constructor -- and voila', it creates the Person object using the same parameter.
If I had done this with the "Prototype" way:
function Person(name){
this.introduce = function(){
console.log("Hi, I am "+this.name);
}
}
function Employee(name, title){
this.name = name; /* ?!?!?!?!? I can't call the proper constructor here */
this.title = title;
}
Employee.prototype= new Person(); /* ?!?!? NO NAME HERE..>? */
Employee.prototype.constructor = Employee;
e = new Employee('tony', 'manager')
e.introduce();
Err.... now what? I can't even complete this: this.name in Employee cannot be set using the proper Person constructor; the creation of a Person object happens only once in the inheritance.
So... what am I missing? Is the first example I gave "the" way to go in my case? And is there a way to have the same result with the second example?
Help!

This kind of prototype inheritance is often done this way:
function Parent() {}
function Child() {
Parent.call(this); // call the constructor of the parent
}
var Constr = function() {};
Constr.prototype = Parent.prototype;
Child.prototype = new Constr();
Child.prototype.constructor = Child;
So the "trick" is to assign the Parent.prototype as prototype to an empty function and set a new instance of this function as prototype of Child.
This is done so that extending Child.prototype does not extend Parent.prototype.
You also have to call the parent's constructor in the child's constructor. I guess this is the part you struggled with. Every function has a call [docs] and apply [docs] method which let's you explicitly set the element this should refer to inside the function.
In your example, it would look like:
function Employee(name,title){
this.title=title;
Person.call(this, name);
}
without assigning the constructor to a property of the instance.
In your example, this.base(name) works, because through assigning the constructor to a property of the instance (and calling it this way), this inside the function refers to that instance.
There are several libraries implementing this pattern, e.g. Google Closure library:
goog.inherits = function(childCtor, parentCtor) {
/** #constructor */
function tempCtor() {};
tempCtor.prototype = parentCtor.prototype;
childCtor.superClass_ = parentCtor.prototype;
childCtor.prototype = new tempCtor();
childCtor.prototype.constructor = childCtor;
};

Related

How to set the constructor of an Object without changing to a new Object?

In this related question, the answer for setting a constructor is like so:
function OldClass() {
alert("old class with incomplete constructor")
}
function ChangedClass(){
alert('new class with same prototype and more complete constructor');
}
ChangedClass.prototype = OldClass.prototype;
var theClassIWant = new ChangedClass();
This is not really setting the constructor, it's making a new object and inheriting the prototype. How can I set the constructor of an Object without changing to a new Object? Is it possible?
P.S. I want something like this:
//non working code
var Foo = function() {}
Foo.prototype.constructor = function(bar_val) {
this.bar = bar_val;
}
var fez = new Foo("cat")
console.log(fez.bar); // outputs: cat;
constructor is a property of the constructor function's prototype, which points to the function itself by default.
When you modify Foo.prototype.constructor, this property points to another function. However, the constructor function Foo remains. So when you create an object, you are still instantiate the constructor function Foo, not the one Foo.prototype.constructor points to.
This is why your code doesn't work. Then let's talk why we need to change the constructor and how to.
In ES5 and before, we take advantage of prototype to simulate a class inheritance mechanism. Which looks like this:
// parent class
function Person(name) {
this.name = name
}
// define parent method
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent properties
this.job = 'Coding'
this.major = major
}
// inherits properties and methods from parent prototype
Coder.prototype = new Person()
// define child method
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
// instantiate a child object
var me = new Coder('Leo', 'JavaScript')
console.log(me) // {name: "Leo", job: "Coding", major: "JavaScript"}
Everything looks perfect, but there a problem:
console.log(me.constructor) // Person
What? Isn't me constructed with Coder? Why?
Go back to the first line of this answer, read it again: constructor is a property of the constructor function's prototype.
Originally Coder.prototype.constructor is Coder itself. But with this line: Coder.prototype = new Person(), it got changed. Coder.prototype.constructor now equals Person.prototype.constructor, which is Person.
Well, some would say, try instanceof. Yes, that works:
me instanceof Coder // true
But it's also true for Person, because Coder is a sub class of it:
me instanceof Person // true
This doesn't make sense so we need to fix the constructor problem. That's why we use Coder.prototype.constructor = Coder after Coder.prototype = new Person(), to get back the original constructor.
Full code looks like this:
// parent class
function Person(name) {
this.name = name
}
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent class
this.job = 'Coding'
this.major = major
}
Coder.prototype = new Person() // inherits parent's prototype
Coder.prototype.constructor = Coder // get back constructor
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
myClass = {
constructor: function(text){
console.log(text);
}
}
let ob = Object.create(myClass);
ob.constructor("old constructor "); //Output: old constructor
myClass.constructor = function(){
console.log("new constructor ")
}
ob.constructor(); //Output: new constructor
You can do this with every property or function of a class.
Watch this Video here. It explains it perfectly.

Difference between creating inheritance using object.create and new operator

Please find my two methods of creating inheritance. Can some one explain me what going on with each type.
Method 1:
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
return this.name;
}
function Employee(name, designation){
Person.call(this, name);
this.designation = designation;
}
Employee.prototype = new Person();
Employee.prototype.constructor = Employee;
Employee.prototype.getDesignation = function(){
return this.designation;
}
new Employee("Jagadish", "Cons");
Method 2:
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
return this.name;
}
function Employee(name, designation){
Person.call(this, name);
this. designation = designation;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.getDesignation = function(){
return this.designation;
}
new Employee("Jagadish", "Cons");
I have inserted the images of console of each object. In first method i can see name property in Person class which is undefined (refer first screenshot).
But in case of second method of inheritance i dont have name property in Person class.
Can someone explain in depth about this behavior and what is happening in background.
There is nothing magical going on here, the program is doing exactly what it is told to do.
When you are calling new Person, you are creating a new object. That object has a name property because you are explicitly assigning to this.name inside the function.
Object.create however creates an empty object, unless it is passed a second argument with property descriptors.
To explain the specific difference between Object.create and new A:
new A():
Create a new object inheriting from A.prototype
Apply A to the new object, i.e. call A.call(newObj)
Object.create(A.prototype):
Create a new object inheriting from A.prototype
So you see, the specific difference between those two calls is that with new the function is applied to the new object, with Object.create is isn't.
Related: Benefits of using `Object.create` for inheritance

Javascript inheritance (through Backbone source code), why Surrogate function in Backbone?

Usual way to implement inheritance in javascript is something like:
function Person(name, surname) {
this.name = name;
this.surname = surname;
}
Person.prototype.whoAmI = function() {
console.log("I'am " + this.name + " " + this.surname);
}
function Ninja() {
Person.apply(this, arguments); // call to parent constructor
}
Ninja.prototype = new Person();
Ninja.prototype.constructor = Ninja;
var ninja = new Ninja("John", "Doe");
ninja.whoAmI();
From backbone what i can see is use of "Surrogate" function like: (very simplified example of what i can extract like example from Backbone source code)
function Person(name, surname) {
this.name = name;
this.surname = surname;
}
Person.prototype.whoAmI = function() {
console.log("I'am " + this.name + " " + this.surname);
}
function Ninja() {
Person.apply(this, arguments);
}
var Surrogate = function() { this.constructor = Ninja; }
Surrogate.prototype = Person.prototype;
Ninja.prototype = new Surrogate();
var ninja = new Ninja("John", "Doe");
ninja.whoAmI();
From what i can understand, these examples work exactly same so why need for Surrogate function.
I find one comment in the source about this:
Set the prototype chain to inherit from parent, without calling
parent's constructor function.
Why not calling parent constructor function?
Why not calling parent constructor function?
Because we want to constructor function to be only called when an instance is created. The Ninja.prototype however is not an instance of Person, it should not have name or surname properties - it should only inherit the whoAmI method. See also What is the reason to use the 'new' keyword at Derived.prototype = new Base for details.
Usual way to implement inheritance in javascript is something like
Only "something like". The correct way is not to call the parent constructor, but we don't need that Surrogate thingy for that. The standard is just to use Object.create:
Ninja.prototype = Object.create(Person.prototype);
Ninja.prototype.constructor = Ninja;
(for compatibility with ES3 environments just shim Object.create instead of littering your source code with Surrogate functions)

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.

Javascript: Inherit method from base class and return the subclass's private variable

I have the following BaseClass defined:
function BaseClass (arg1,arg2,arg3) {
//constructor code here then -
var privateVar = 7500;
this.getPrivateVar = function() { return privateVar; };
}
I want to have the following subclass which allows changing privateVar like so:
function SubClass (arg1,arg2,arg3,privateVar) {
//constructor code here then -
var privateVar = privateVar;
}
SubClass.prototype = new BaseClass();
Now I want SubClass to inherit the getPrivateVar method. However, when I try this, it always returns 7500 which is the value in the BaseClass and not the value of privateVar.
In other words, is it possible to inherit a BaseClass's public methods but have any references in them refer to the SubClass's properties? And how would I do that?
By the sound of things, it's impossible. The idea was to automate a code-checker for my students code (I tutor kids) but I'll just have to find another way. Thanks anyway.
You are mixing Javascript object model with scoped variables which do not interoperate*.
The inherits idiom of doing SubClass.prototype = new BaseClass(); only works when you are using prototypes and constructors naturally:
function BaseClass(arg1, arg2, arg3) {
this._privateVar = 7500;
}
BaseClass.prototype.getPrivateVar = function() {
return this._privateVar;
};
function SubClass(arg1, arg2, arg3, privateVar) {
}
SubClass.prototype = new BaseClass();
//Better way to do it is
//SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
Before you argue that anyone can access the property by just writing _, I could argue back that anyone can access any private in Java, PHP or C# by using reflection. Or using instance_eval or send in Ruby and so on. So it's out of your hands anyway.
*None or most of these don't work when you use scoped variables depending on implementation:
Enumerability
Writability
First-class Accessors
Sealedness, Frozedness and state of Extension
Reflection through getPropertyNames or keys
instanceof operator
Generic methods
Inheritance
The way you defined privateVar makes it a local variable inside the scope of BaseClass "constructor". Like Neal said, you cannot inherit nor "see" it from any inherited class.
You can use a closure like Neal said (but this can be a memory overkill depending on your usage context), or make the variable an instance variable:
function BaseClass (arg1,arg2,arg3) {
//constructor code here then -
this.privateVar = 7500;
this.getPrivateVar = function() { return this.privateVar; };
}
function SubClass (arg1,arg2,arg3,privateVar) {
//constructor code here then -
this.privateVar = privateVar;
}
SubClass.prototype = new BaseClass();
var subClass = new SubClass(1,2,3,4000);
console.log(subClass.getPrivateVar());
The idea of having a private variable is that is should not be accessible outside of the scope in which is was declared. However there are a few ways to achieve what you wish to do. For example, you could make the default value of privateVar in BaseClass dynamic:
function BaseClass(arg1,arg2,arg3) {
var privateVar = BaseClass.privateVar;
this.getPrivateVar = function () {
return privateVar;
};
}
BaseClass.privateVar = 7500;
Now you can create SubClass as follows:
function SubClass(arg1, arg2, arg3, privateVar) {
var args = Array.prototype.slice.call(arguments, 0, 3); // the first 3 args
var defaultPrivateVar = BaseClass.privateVar; // save the old value
BaseClass.privateVar = privateVar; // set a new default
BaseClass.call(this, args); // call super
BaseClass.privateVar = defaultPrivateVar; // restore old value
}
SubClass.prototype = Object.create(BaseClass.prototype); // inherit new way
Now all you need to do is simply create an instance of SubClass: http://jsfiddle.net/Pytkj/
privateVar is a local variable of BaseClass. It cannot be inherited or changed by the subclass.
You can encapsulate the parent and subclass in the same scope like so:
(function(){
var privateVar = 7500;
function BaseClass (arg1,arg2,arg3) {
//constructor code here then -
this.getPrivateVar = function() { return privateVar; };
}
function SubClass (arg1,arg2,arg3,privateVar) {
//constructor code here then -
}
SubClass.prototype = new BaseClass();
return SubClass;
})();
You would not. And even if you could, the property could not be called "private" any more. Maybe "protected".
Languages that lack different access levels just use public attributes and some sort of a naming convention (like calling them __semiPrivateVar).
There are some different solutions, but they are not really describable in terms of OO (what you really have are not classes and attributes but constructors, scopes and variables).
inherit a BaseClass's public methods but have any references in them refer to the SubClass's properties?
No, that's impossible. The method created inside the BaseClass constructor scope will always reference the variables from that scope, you cannot change it. It's a variable, not a property of the object.
However, you're doing the inheritance wrong. You have a BaseClass instance from which you inherit and with which all SubClass instances will share their getPrivateVar method. Get them an own one! To do so, you can apply the parent constructor on the child instance, creating a new closure scope and a new method. And don't use new!
function SubClass (arg1,arg2,arg3) {
BaseClass.call(this);
}
// or, if you need a reference to the variable:
function SubClass (arg1,arg2,arg3) {
// you have to create it on your own
var privateVar = arguments[3]; // or use a formal parameter
// and create `getPrivateVar` yourself
this.getPrivateVar = function() { return privateVar; };
}
SubClass.prototype = Object.create(BaseClass.prototype);

Categories