I have the following code I am trying to run, I get an error at the last line. From my understanding x's prototype chain looks good. What am I missing here
var Child = (function(){
function Parent(){
this.name ="parent";
this.parentHello = function(){
console.log("parent hello "+this.name);
};
}
return function(){
function Bridge(){
}
Bridge.prototype = new Parent();
this.constructor.prototype = new Bridge();
this.hello = function(){
console.log('hello');
};
};
})();
var x = new Child();
console.log(x.constructor);
console.log(x.constructor.prototype);
x.hello();
x.constructor.prototype.parentHello(); // This works
x.parentHello(); // TypeError: x.parentHello is not a function
This is modeled after an existing code, I cannot change the structure of it. I modified the original a little bit to post as question.
Update: Why the original doesn't work. You've asked in the comments to the question why it doesn't work. I'm not going to dig up the actual specifications for this for you, but the explanation is straightforward.
You do this:
this.constructor.prototype = new Bridge();
inside the constructor function. That's too late. When the JS Engine creates an object with new it looks to the constructor function you're calling, creates a new empty object, then assigns the prototype of that object from the constructor's prototype. Then it applies the function in the context of this newly created object. Inside there, you reassign the prototype of the constructor, but it's too late.
It's easy to see that this is the issue by just doing this:
var x = new Child();
x.parentHello(); // throws an exception
var y = new Child(); // gets the updated prototype
y.parentHello(); // works as expected
But the big question is why you would want to reassign the prototype from within the constructor. It is an extremely confusing notion, even if it were to work properly.
We now return you to your originally scheduled answer.
The reason this doesn't work is that you're confusing levels, and trying to do something inside a constructor function that really should be done outside of it. Below is what I think of as the minimal modification of your code to make it work. It is not how I would suggest actually writing this, but it's a starting place for discussion:
var Child = (function(){
function Parent(){
this.name ="parent";
this.parentHello = function(){
console.log("parent hello "+this.name);
};
}
function Child() {
this.hello = function(){
console.log('hello');
};
}
function Bridge(){}
Bridge.prototype = new Parent();
Child.prototype = new Bridge();
Child.prototype.constructor = Parent;
return Child;
})();
var x = new Child();
x.hello(); //=> logs "hello"
x.parentHello(); //=> logs "parent hello parent"
Now that last block really should become an inherit function or some such:
var inherit = function(Parent, Child) {
function Bridge(){}
Bridge.prototype = new Parent();
Child.prototype = new Bridge();
Child.prototype.constructor = Parent;
return Child;
}
var Child = (function(){
function Parent(){
this.name ="parent";
this.parentHello = function(){
console.log("parent hello "+this.name);
};
}
function Child() {
this.hello = function(){
console.log('hello');
};
}
return inherit(Parent, Child);
})();
Often these days, these things are handled in one of two different ways, though. This version is pretty old-school. Instead now, if you're using es6, there is a class syntax that does pretty much the equivalent of this. And if not, techniques using Object.create are very common.
I'm going to attempt to both explain what was wrong with your code and show a better way to achieve the same inheritance you have now.
Analysis of your code:
Child is a constructor function.
In a private scope of that function is the Parent() constructor
Calling the Child function with new attepts to return a new object that initializes the Bridge constructor and prototype and then attempts to set the constructor of the current object's prototype to new Bridge().
I'm guessing here since you don't explicitly describe what you're trying to accomplish, but it looks like maybe you're trying to create two levels of inheritance where Parent is the base, then Bridge derives from Parent, then Child derives from Bridge.
But, you can't be setting the prototype for Child in the constructor of Child. That's too late to be setting it because the first Child object has already been created.
So, when you do x = new Child();, x will just be a Child object without inheriting from Bridge. Thus, there is no .parentHello() method on it.
When you create new objects with inheritance, you also need to call the inherited constructors so they can properly initialize their instances.
Fixing the code:
Since the inheritance structure here is fixed and completely known ahead of time, there is no reason to try to do this dynamically. It should be assigned once at the time the Child IIFE runs, not inside the Child constructor. This will both fix timing issues and make the code run properly.
Further, it's 2016, so we should be using Object.create() to create prototypes, not new.
And, objects needs to call the constructors of the things they inherit from.
Here's what I would suggest (you can run this snippet and look in the debug console):
var Child = (function(){
// define base class
function Parent(){
this.name ="parent";
this.parentHello = function(){
console.log("parent hello "+this.name);
};
}
Parent.prototype.constructor = Parent;
// define Bridge which inherits from Parent
function Bridge() {
// call parent constructor
Parent.call(this);
}
Bridge.prototype = Object.create(Parent.prototype);
Bridge.prototype.bridgeHello = function() {
console.log("bridge hello");
}
Bridge.prototype.constructor = Bridge;
function Child() {
// call parent constructor
Bridge.call(this);
this.hello = function(){
console.log('hello');
};
}
Child.prototype = Object.create(Bridge.prototype);
Child.prototype.constructor = Child;
return Child;
})();
var x = new Child();
console.log(x);
console.log(x.constructor);
x.hello();
x.bridgeHello();
x.parentHello();
And, here's a similar implementation using the more modern ES6 class syntax (you can run this snippet in a browser that supports ES6 classes such as Chrome, Firefox or Edge):
"use strict";
var Child = (function(){
// base class
class Parent {
constructor() {
this.name = "parent";
}
parentHello() {
console.log("parent hello "+this.name);
}
}
// define Bridge which inherits from Parent
class Bridge extends Parent {
constructor() {
super();
this.name = "bridge";
}
bridgeHello() {
console.log("bridge hello");
}
}
class Child extends Bridge {
constructor() {
super();
this.name = "child";
}
hello() {
console.log('hello');
}
}
return Child;
})();
var x = new Child();
console.log(x);
console.log(x.constructor);
x.hello();
x.bridgeHello();
x.parentHello();
Related
JavaScript uses a Prototype system, which is fundamentally different than a Class system. This is my first serious encounter with the language. I had fooled around with it previously, but this is the first time I built a system with proper OO, inheritance, polymorphism, etc.
From what I read there seems to be a few common methods to do member function inheritance in Javascript. Assuming you have a parent foo as following
foo = function(){ this.one = 1; }
foo.prototype.func1 = function(){return this.one;}
The MDN Introduction to JavaScript Inheritance suggests the naive approach of invoking the parent's method in the context of the child, as shown below.
bar = function(){ foo.call(this); }
bar.prototype = Object.create(foo.prototype);
bar.prototype.func1 = function(){ return this.one + foo.prototype.func1();}
This has the advantage of being simple to understand, but can become cumbersome as pointed out in this Salsify Blog post. The blog post outlines an alternate method where a super property is defined in the child prototype, and the name of each member function is attached as a property to the method. This method, however, relies on the caller property of a method, which the article points out will soon be deprecated. Rather than duplicate the entire post, I believe a summary of the important points are these
Object.defineProperty(bar.prototype, "super", {
get: function get() {
...
// methodName is set as a property on each method in an omitted code segment
methodName = get.caller.methodName;
...
Object.getPrototypeOf(this.prototype)[methodName]
}
}
Which is to say that you find the method with the same name in your prototype's prototype. I was wondering if this can be done in a simpler manner, without having to attach the method name as a parameter and without the Function.caller.
foo.prototype.super = function(method) {
superMethod = Object.getPrototypeOf(this.constructor.prototype)[method];
return superMethod.call(this, Array.prototype.slice.call(arguments, 1));
}
bar.prototype.func1 = function(){ return this.one + super('func1'); }
I'm making a number of assumptions in the above, I'd like to verify some assumptions.
new bar().constructor.prototype === Object.getPrototypeOf(new bar())
If the above is always true, is one preferable over the other?
The Parent's member function will always live in the child's prototype's prototype (assuming that neither of the prototypes were mutated after object creation)
That Object.getPrototypeOf() is not the "language support for accessing super methods" that the blog refers to as being added in ES6
If Object.getPrototypeOf() isn't that language support, what is?
After seeing the error of using this, which does not change throughout the execution and always refers to the instance of the subclass, I've revisited and am thinking I need something like this
Grandfather = function(){};
Grandfather.prototype.function1 = function(){console.log("I am the Grandfather");};
Father = function(){Grandfather.apply(this);};
Father.prototype = Object.create(Grandfather.prototype);
Father.prototype.function1 = function f(){ f.super(); console.log("I am the Father");};
Father.prototype.function1.super = Grandfather.prototype.function1;
Child = function(){Father.apply(this);}
Child.prototype = Object.create(Father.prototype);
Child.prototype.function1 = function f(){ f.super(); console.log("I am the Child");};
Child.prototype.function1.super = Father.prototype.function1;
c = new Child();
c.function1();
// I am the Grandfather
// I am the Father
// I am the Child
And so the question becomes, how to set the super property on to each function in some automatic way?
One such way to do this is shown below, it has the benefit that functions added to the prototype after objects are instantiated still receive the benefit of being able to call superFunc, whereas an approach that sets a super property at class extension time would not set such a property if functions are added to the prototype later.
The downsides of this approach are that it only works in single threaded environment and that it requires functionality inherited from a common base class. It is not threadsafe since some state is held in a what is effectively a static variable of the function. This is fine for my purposes since browsers still have single threaded JavaScript. The requirement that all classes inherit from some base class containing this method isn't a huge blocker (especially if you do a "bad thing" and insert this into Object's prototype).
Grandfather.prototype.superFunc = function f(funcName){
currentPrototype = Object.getPrototypeOf(f.startingPrototype || Object.getPrototypeOf(this));
f.startingPrototype = currentPrototype;
return currentPrototype[funcName]();
}
Child.prototype.function2 = function(){this.superFunc('function2'); console.log("Still in the Child");};
Father.prototype.function2 = function(){this.superFunc('function2'); console.log("Still in the Father");};
GrandFather.prototype.function2 = function(){console.log("Still in the Grandfather");};
c = new Child();
c.function2();
// Still in the Grandfather
// Still in the Father
// Still in the Child
Question 1
new Bar().constructor.prototype should equal Object.getPrototypeOf(new Bar()), provided you haven't overrided Bar.prototype.constructor or Bar.prototype, or return a different object in the Bar constructor. Here's an example:
function Bar() {}
var foo = new Bar();
foo.constructor.prototype === Object.getPrototypeOf(foo); // true
function Bar2() {}
var foo2 = new Bar2();
Bar2.prototype = {};
foo2.constructor.prototype === Object.getPrototypeOf(foo2); // false
function Bar3() {}
var foo3 = new Bar3();
Bar3.prototype.constructor = function NotBar3() {};
foo3.constructor.prototype === Object.getPrototypeOf(foo3); // false
Question 2
If you're looking to get the actual prototype of an object, use Object.getPrototypeOf, as that's unaffected by any of the changes shown above.
Question 3
No, you will not be able to access Foo from new Bar(). In your example, new Bar() would not inherit from Foo.prototype and as a result, there's no way to access Foo unless you make it inherit from Foo.prototype or assign Foo to a property of new Bar() or Bar.prototype.
Question 4/5
No, that's not what they're referring to. ES6 will introduce a separate class contruct, where super takes on a special meaning (similar to how super works in other languages with classes). Here's an example of how classes work in ES6:
class Foo {
constructor() {
this.one = 1;
}
func1() {
return this.one;
}
}
class Bar extends Foo {
func1() {
return this.one + super();
}
}
When you use super in the way you do it'll break when inheritance is more than 2 levels.
Assuming you'd use it the following way:
//changed super to this.super since super is not shown to exist in global scope
bar.prototype.func1(){ return this.one + this.super('func1'); }
See the following example:
function GrandFather(){
this.i = 0;
};
GrandFather.prototype.test = function(){
console.log('test in GrandFather');
};
function Father(){
GrandFather.call(this);
};
Father.prototype = Object.create(GrandFather.prototype);
Father.prototype.constructor = Father;
Father.prototype.super = GrandFather.prototype;
Father.prototype.test = function(){
console.log('test in Father');
//prevent too many recursions
this.i++;
if(this.i>5){
return;
}
this.super.test.call(this);//because test in child was called
// with Child instance as invoking object this will be Child
// and this.super will be Father.prototype
};
function Child(){
Father.call(this);
}
Child.prototype = Object.create(Father.prototype);
Child.prototype.constructor = Child;
Child.prototype.super = Father.prototype;
Child.prototype.test = function(){
console.log('test in Child');
this.super.test.call(this);//because invoking object is Child
//this.super in Father is Child
};
var c = new Child();
c.test();
It's also common practice to start a constructor function with a capital so it's better to use Foo and Bar for constructor function names.
If you want to go through all the trouble of simulating super in JavaScript then the following way would be slightly more robust: http://ejohn.org/blog/simple-javascript-inheritance/
// Sim.App - application class (singleton)
Sim.App = function()
{
this.renderer = null;
this.scene = null;
this.camera = null;
this.objects = [];
}
// Constructor
EarthApp = function()
{
Sim.App.call(this);
}
// Subclass Sim.App
EarthApp.prototype = new Sim.App();
=============================================
In the above, I don't understand why the author used this statement
EarthApp.prototype = new Sim.App();
He could have used
EarthApp = new Sim.App();
Please help me understand the use of 'prototype' within that statement .
Prototypes are a fundamental piece in Javascript's inheritance model. I recommend you read about it, because without understading it you'll not "get" JS fully.
Having that said, assinging an object as a function's prototype makes this object be in a prototype chain of every instance of this function created afterwards.
The way prototype chain works is (more or less) (see example below):
You try to access "foo" variable in an object
If this object have "foo", return it's value.
If this object does not have "foo", look at it's prototype ('Sim.App' instance in your case) - does it have "foo"? If so, return it's value.
If object's prototype does not have a "foo", look at prototype's prototype - and so on, up through the chain.
If you want to read more on that, have a look at this article.
Example - consider:
var Sim = {};
Sim.App = function () {
this.foo = 'sim';
}
EarthApp = function () {
}
EarthApp.prototype = new Sim.App();
var earth = new EarthApp();
// I can access earth.foo even though 'earth' is an instance of 'EarthApp'
// and not 'Sim.App'. That's because instance of 'Sim.App' is in
// earth's prototype chain.
console.log(earth.foo);
The line
EarthApp.prototype = new Sim.App();
...creates a Sim.App object and assigns it to the prototype property of the EarthApp function. That means that when we do this:
var e = new EarthApp();
...the e object will get the object from EarthApp.prototype as its prototype, giving it access to the properties and methods of that object.
FWIW, the inheritance implemented by that code isn't really ideal, because it's calling the Sim.App constructor to create the EarthApp.prototype object, then calling it again to initialize instances. If you want to chain constructors together in that way, here's the more correct way to do it:
// Reusable `derive` function
// Set up `child`'s `prototype` property to be based on `parent`'s `prototype` property
function derive(child, parent)
{
function ctor()
{
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.prototype.constructor = parent;
}
// Sim.App - application class (singleton)
Sim.App = function()
{
this.renderer = null;
this.scene = null;
this.camera = null;
this.objects = [];
};
// Constructor
EarthApp = function()
{
Sim.App.call(this);
};
// Subclass Sim.App
derive(EarthApp, Sim.App);
You might want to check out my Lineage helper script, which does the above and handles all the plumbing required to handle "supercalls" correctly and such.
It's also worth noting that this is just one way to use JavaScript's prototypical inheritance, which is tremendously flexible.
The code is here:
Father.js
(function(){
function father(){
};
father.prototype.init = function(){
console.log('father');
}
})()
Child.js
(function(){
function child(){
}
child.prototype.init = function(){
console.log('child');
}
var father = new father();
})()
I have 2 questions:
How can I call father object or child object between script tag or any third javascript files that I create ?
Second: how can I call the father object inside child class.
I am new to JS and have some problems with OOP in javascript.
Thank you very much for your help
You should assign the result of the anonymous function to a variable that way you can use it without leaking what's inside of the IIFE (Immediately Invoked Function Expression), thus encapsulating everything but the constructor:
var Father = (function(){
// Private stuff...
function Father(){}
Father.prototype.something = function(){};
return Father; // Public constructor
}());
Now you can use Father in your Child class, or better yet, use the same pattern but pass the parent class as parameter to the IIFE:
var Child = (function(_parent){
function Child() {
_parent.apply(this, arguments); // inherit properties from Parent class
}
Child.prototype = Object.create(_parent.prototype); // inherit Parent prototype
Child.prototype.something = function(){};
return Child;
}(Father));
Answer to question one is you define father and child in the global scope:
function father(){
};
father.prototype.init = function(){
console.log('father');
}
function child(){
}
child.prototype.init = function(){
console.log('child');
}
// can't name your var father because it'll overwrite the father function
var dad = new father();
You can use namespacing to restrict the amounts of variables in the global scope:
in father.js:
var myApp=myApp || {};
myApp.father=...
in child.js:
var myApp=myApp || {};
myApp.child=...
var dad = new myApp.father();
To call father object in child you can do father.call(this); making all the father properies in the father function defined as this.someprop=... part of the just created child. If you just want to access the father instance named dad (see code above) then you can do dad.init()
More on inheritance and prototype here:
Prototypical inheritance - writing up
I've set up a fiddle : http://jsfiddle.net/J75Zz/
It doesn't matter on how many .js files you "distribute" your code, it's just "one code block", which get's executed (well, almost ...).
You should name Objects with Capitals, there's already a clash between object father and variable father.
I'm trying to fully understand how 'extend' works in javascript.
Here's a simple extend function I found on google
function extend(child, parent) {
var f = function() {}
f.prototype = parent.prototype;
var i;
for( i in parent.prototype ) {
child.prototype[i] = parent.prototype[i];
}
child.prototype.constructor = child;
child.parent = parent;
}
it works, but I don't understand "child.prototype.constructor = child" part. The function still works without it.
What's the purpose of the line?
No. Where did you find that? It mixes two approaches:
The classical prototype inheritance
function inherit(child, parent) {
var f = function() {}
f.prototype = parent.prototype;
child.prototype = new f();
child.prototype.constructor = child;
}
This function creates a new object that inherits directly from the prototype object of the parent function. It is an old-style synonym for Object.create(). With that, a prototype chain is set up - all instances of child inherit from the parent.prototype as well. Because a new object is generated to overwrite child.prototype, the "constrcutor" property needs to be updated.
The mixin inheritance
This function just loops over all properties of the parent's prototype object, and copies them onto the child's prototype object. This is quite what the common helper function extend does. It does not reset the "prototype" property of the child function, but it also does not set up a inheritance chain.
function extend(child, parent) {
for (var i in parent.prototype ) {
child.prototype[i] = parent.prototype[i];
}
}
You are right, the line
child.prototype.constructor = child;
is quite useless here - the "constructor" property is not enumerable and will not be affected by the extend.
Also, your function sets a "parent" property of the child function object to the parent function, which is not required:
child.parent = parent;
It appears to me that the 'child.prototype.constructor' is a base/vanilla implementation of the object, it allows other objects to extend from it without inheriting the same parent. Hence why it is declared prior to 'child.parent = parent'.
This may not directly answer your question, but I would like to reccomend you to use the extend implementation of John Resig:
Simple JavaScript Inheritance
It allows you to create a constructor named init, like this:
var MyClass = Class.extend({
init: function() {
console.log("Running a constructor");
}
});
and instanciate objects like this (normal):
var obj = new MyClass();
This example shows how to inherit a class in javascript
var a = function(){
// class a constructor
this.a_priviligiate_var = 1;
}
a.prototype.a_public_var = 2;
var b = function(){
// class b constructor
// super call of class a constructor
// this line makes b class to inherit all privileged vars
b.prototype.constructor.call(this)
this.b_priviligiate_var = 3;
}
b.prototype.b_public_var = 4;
b.prototype = new a();
var c = new b();
Defining a claas:
var a = function(){
// class a constructor
this.a_priviligiate_var = 1;
}
a.prototype.a_public_var = 2;
Defining another class:
var b = function(){
// class b constructor
// super call of class a constructor
// this line makes b class to inherit all privileged vars
b.prototype.constructor.call(this)
this.b_priviligiate_var = 3;
}
b.prototype.b_public_var = 4;
Setting the super(parent) class. This line copies all b.prototype
b.prototype = new a();
Creating a instance of c
var c = new b();
We write a lot of JavaScript code to run our automated testing using a tool called TestComplete. In several cases I've set up inheritance trees using the following syntax:
function Parent()
{
...
//some inline code here executes on object creation
}
Child.prototype = Parent;
Child.prototype.constructor = Child;
function Child()
{
Parent.call(this);
...
}
The reason I've used
Child.prototype = Parent;
instead of
Child.prototype = new Parent();
is because there is code that is executed on the creation of a new object in the parent in some cases. Setting the prototype this way has never been an issue, in that I've always been able to call all the functions defined in the Parent after having created a Child.
I suspect, however, I've actually broken the prototype chain in doing this and I've been saved by the fact that all the methods we define are defined inline (ie. inside the constructor function) and not using the object.prototype.method = ... syntax, and so the fact the chain is broken has gone unnoticed.
So I have two questions; have I broken the chain, and what are the side effects of breaking the prototype chain in JavaScript?
When you "break" the prototype chain like this, you cannot access Parent.prototype.* methods and properties in Child instances and the instanceof operator does not work (new Child() instanceof Parent === false).
I understand why you don't want to use the new keyword for the inheritance. There is, however, a little trick to inherit the parent's prototype whilst not executing the parent's constructor:
var Parent = function () { ... };
var Child = function () {
Parent.call(this);
...
};
var Fn = function () {};
Fn.prototype = Parent.prototype;
Child.prototype = new Fn();
Child.prototype.constructor = Child;
Ok, this code will run for you and allows access to the prototype. It involves making the parent an object literal and you can call a prototype method in your child's "constructor"
var Parent = {
testMethod1 : function() {
alert('testMethod1');
}
}
Parent.testMethod2 = function() {alert('testMethod2');}
Child.prototype = Parent;
//Child.prototype.constructor = Child;
function Child()
{
alert('im ready');
Child.prototype.testMethod1();
}
var child1 = new Child();
child1.testMethod1();
child1.testMethod2();
Parent.testMethod3 = function() {alert('testMethod3');}
child1.testMethod3();
and if you wanted to do away with 'new' you could use Object.create()
var Parent = {
testMethod1 : function() {
alert('testMethod1');
}
}
Parent.testMethod2 = function() {alert('testMethod2');}
var child1 = Object.create(Parent);
child1.testMethod1();
child1.testMethod2();
Parent.testMethod3 = function() {alert('testMethod3');}
child1.testMethod3();
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
In the second case you would need to call a function as your "constructor" after you create()'d the object, but it's true protototypal inheritance.