Using pure JavaScript to do inheritance, this is what I usually do:
function A() {}
A.prototype.run = function () {};
function B() {}
B.prototype = new A;
B.prototype.constructor = B;
Since there is no arguments to pass into the constructor, new A has nothing to complain about. Now, I haven't figured out a good way to do inheritance if the constructor has arguments to pass. For example,
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {}
B.prototype = new A;
B.prototype.constructor = B;
I could pass some arbitrary values like:
B.prototype = new A(null, null);
In some cases, I may need to validate x and y in the constructor of A. In some extreme cases, I need throw errors when checking x or y. Then, there is no way for B to inherit from A using new A.
Any suggestions?
Thanks!
Well, if you want to make B.prototype an object that inherits from A.prototype, without executing the A constructor, to avoid all possible side-effects, you could use a dummy constructor to do it, for example:
function tmp() {}
tmp.prototype = A.prototype;
B.prototype = new tmp();
B.prototype.constructor = B;
You could create a function to encapsulate the logic of the creation of this new object, e.g.:
function inherit(o) {
function F() {}; // Dummy constructor
F.prototype = o;
return new F();
}
//...
B.prototype = inherit(A.prototype);
B.prototype.constructor = B;
If you target modern browsers, you could use the ECMAScript 5 Object.create method for the same purpose, e.g.:
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
//..
Although this is an old topic, I thought I'd respond anyway.
Two ways to do it:
Although the Pseudo Classical way is the most popular, it has its down sides since it needs to call the parent constructor once in the child constructor and once while inheriting the prototype. Besides, the child's prototype will contain all the properties of the parent constructor which will anyway get overwritten when the child constructor is called. My personal choice is Prototypal Inheritance.
1. Pseudo Classical Inheritance:
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {
A.call(this,x,y);
}
B.prototype = new A();
B.prototype.constructor = B;
2. Prototypal Inheritance:
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {
A.call(this,x,y);
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
The problem is that you can't easily create a prototype object for B since invoking the constructor of A can't be done. This is due to the parameters for the constructor being unknown before new B is executed. You need a dummy constructor function to construct a prototype for B that links to A's prototype.
B.prototype = (function(parent){
function protoCreator(){};
protoCreator.prototype = parent.prototype;
// Construct an object linking to A.prototype without calling constructor of A
return new protoCreator();
})(A);
Once you've got the prototype object for B set up, you need to ensure to call the constructor of A in the constructor of B.
function B(x, y) {
// Replace arguments by an array with A's arguments in case A and B differ in parameters
A.apply(this, arguments);
}
You should now be able to instantiate B by calling new B(x, y).
For a complete same including parameter validation in A see a jsFiddle.
In your original code you are setting B.prototype.constructor = B. I'm not getting why you are doing this. The constructor property does not influence the inheritance hierarchy for which the prototype property is responsible. If you want to have the named constructor contained in the constructor property you'd need to extend the code from above a little:
// Create child's prototype – Without calling A
B.prototype = (function(parent, child){
function protoCreator(){
this.constructor = child.prototype.constructor
};
protoCreator.prototype = parent.prototype;
return new protoCreator();
})(A, B);
Using the first definition of B.prototype you'd get the following results:
var b = new B(4, 6);
b.constructor // A
console.info(b instanceof A); // true
console.info(b instanceof B); // true
With the extended version, you'll get:
var b = new B(4, 6);
b.constructor // B
console.info(b instanceof A); // true
console.info(b instanceof B); // true
The cause for the different output is that instanceof follows up the whole prototype chain of b and tries to find a matching prototype object for A.prototype or B.prototype (in the other call). The b.constructor prototype does refers to the function that was used to define the instances prototype. In case you wonder why it does not point to protoCreator this is because its prototype was overwritten with A.prototype during the creation of B.prototype. The extended definition as show in the updated example fixes this constructor property to point to a more appropriate (because probably more expected) function.
For daily use, I'd recommend to discard the idea of using the constructor property of instances entirely. Instead do use instanceof since its results are more predictable/expected.
Consider this:
function B( x, y ) {
var b = Object.create( new A( x, y ) );
// augment b with properties or methods if you want to
return b;
}
And then
var b = new B( 12, 13 );
Now b inherits from an instance of A, which in turn inherits from A.prototype.
Live demo: http://jsfiddle.net/BfFkU/
Object.create isn't implemented in IE8, but one can easily manually implement it:
if ( !Object.create ) {
Object.create = function ( o ) {
function F() {}
F.prototype = o;
return new F();
};
}
This can be placed inside a ie8.js file which is loaded only for IE8 and below via conditional comments.
Related
I'm studying javascript and have a trouble to understand the 2nd part in the explanation below. Is it possible for any of you shed me the light on this matter
"The actual prototype of a constructor is function.prototype since constructors are functions. Its prototype property will be the prototype of instances created through it but is not its own prototype"
I think a series of comparisons will help you figure it out.
The actual prototype of a constructor is function.prototype since constructors are functions
function IamAConstructorFunc() {} // A constructor function
IamAConstructorFunc.constructor // function Function()
IamAConstructorFunc.constructor.prototype // function Empty()
IamAConstructorFunc.constructor.prototype === Function.prototype // True
IamAConstructorFunc.constructor.prototype === Object.prototy // False
Its prototype property will be the prototype of instances created through it
var IObj = new IamAConstructorFunc; // Instance of IamAConstructorFunc
IObj.__proto__ === IamAConstructorFunc.prototype // True
IObj.constructor === IamAConstructorFunc // True
IObj instanceof IamAConstructorFunc // True
but is not its own prototype
IamAConstructorFunc has a prototype but it's not it's own prototype, it's an instance of Object and that instance prototype is:
IamAConstructorFunc.prototype.__proto__ === Object.prototype // True
OK, here's an example:
function Widget() {
console.log('Widget constructor invoked');
}
Function.prototype.sayHi = function() { console.log('Function prototype.sayHi invoked'); };
Widget.prototype.sayHi = function() { console.log('Widget prototype.sayHi invoked') };
var w = new Widget();
console.log('Calling w.sayHi()');
w.sayHi();
console.log('Calling Widget.sayHi()');
Widget.sayHi();
This will produce the following log output:
Widget constructor invoked
Calling w.sayHi()
Widget prototype.sayHi invoked
Calling Widget.sayHi()
Function prototype.sayHi invoked
Calling w.sayHi() is calling a method on the Widget object, while calling Widget.sayHi() is invoking a method on a function. They have two different prototypes.
That's way too complicated.
A function can be used to create an object.
function MyFunc(a, b) {
this.a = a;
this.b = b;
}
var myObj = new MyFunc(a, b);
The function's prototype can be used to create functions that work on the object.
MyFunc.prototype.sum = function() {
return this.a + this.b;
}
var myObj = new MyFunc(2, 3);
var true = (myObj.sum() === (2 + 3));
It's probably easier viewing an example.
function Person(first, last) {
this.first = first;
this.last = last;
}
Person.prototype.fullName = function() {
return this.first + " " + this.last;
}
var fred = new Person("Fred", "Flintstone");
var barney = new Person("Barney", "Rubble");
var output = document.getElementById("output");
output.innerHTML += fred.fullName() + "<br>\n";
output.innerHTML += barney.fullName() + "<br>\n";
#output {
color:blue;
font-weight:bold;
}
<div id="output">
</div>
I think the problem is the confusion between the prototype property of a function and the internal prototype, that every object has.
Every function has a prototype property. This property is like any other property of any object. The only thing special about it is, that it will be used as the internal prototype for any object, that is created by that function.
function A() {
}
//add property c to public prototype property of A
A.prototype.c = 1;
//create a new instance -> a will get A's prototype property as internal prototype
a = new A();
//a has therefore access to the property c, that was defined earlier
console.log(a.c); //1
Since functions are also objects in JavaScript, they also have an internal prototype.
function A() {}
//apply is part of A's prototype chain.
//It's defined on its internal prototype objects,
//which was created by its own constructor, named "Function"
A.apply(this, []);
This statement almost drove me crazy but I ended up understanding it. In fact, in JavaScript, a constructor, when created get automatically assigned a property called prototype.
This property will be used by all instances created through this constructor as their own prototype and DOES NOT REFER ANYWAY TO the actual prototype of the constructor itself. Actually, the constructor prototype is Function.prototype.
var Cat = function() {};
Cat.__proto__ === Function.prototype; // true
var kitty = new Cat;
kitty.__proto__ === Cat.prototype; // true
It is normal because the Cat (our constructor) is a Function per se so it derived from Function.prototype. And kitty came out of the new keyword call on Cat so it derived from Cat.prototype.
So in the statement :
The actual prototype of a constructor is function.prototype since constructors are functions.
The actual prototype refers to __proto__ property of our constructor (Cat).
Its prototype property will be the prototype of instances created through it but is not its own prototype.
Its prototype property refers to .prototype
in this case
var A = function(){
this.d = 123;
}
A.prototype.c = 999;
A.prototype.d = 333;
var B = (new A()).constructor;
console.log(""+B);
console.log(new A().d); // 123
console.log(new B().d); // 123
console.log(new A().c); // 999
console.log(Object.getPrototypeOf(new B()).c); // 999 why?
A and B share same constructor
but B is not A, why has same prototype of A?
in this case
var A = function(){
this.d = 123;
}
A.prototype.c = 999;
A.prototype.d = 333;
var B = A.constructor;
console.log(""+B);
console.log(new A().d); // 123
console.log(new B().d); // undefined
console.log(B.d); // still undefined
console.log(new A().c); // 999
console.log(Object.getPrototypeOf(new B()).c); // undefined
B is constructor of A and not of his instance
what is B? how to access constructor of A with no instance of A?
When you call new A(), you create a new A object whose prototype is A.prototype. When you ask for (new A()).constructor, you're accessing the constructor property from the prototype chain of that A instance; this would be A.prototype.constructor.
A itself is a Function object. That is to say: A is an instance of Function. When you ask for A.constructor, you're accessing the constructor property from the prototype chain of that Function instance; this would be Function.prototype.constructor.
In your first case, B and A are references to the exact same function. It's totally expected that the results of new A() and new B() would have the same properties and the same prototype chain.
In your second example, B is the Function constructor -- i.e., a function that constructs functions. Calling new B() creates a new Function object. Thus, the result of new B() has none of the same properties as an A instance.
To tell the difference you might want to look at what is A and what is new A():
c = new A(); // This is an instance of A. The constructor property is A.
console.log(c.constructor) // function() { this.d = 123; }
console.log(new c.constructor()) // Creates another instance of A.
console.log(Object.getPrototypeOf(new c.constructor())) // A {c: 999, d: 333}
var c = A; // This is a function. The constructor property is a base Function.
console.log(c.constructor) // function Function() { [native code] }
console.log(new c.constructor()) // Creates instance of base Function.
console.log(Object.getPrototypeOf(new c.constructor())) // function Empty() {}
Without the new operator on your custom constructor (A) you are not creating an instance of A.
More information on new operator: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
Even though it's already answered, I did not see it made clear that B is A (oops, its late missed apsillers mentioned it):
var A = function(){};
var B = (new A()).constructor;
console.log(B===A,B===A.prototype.constructor
,A.prototype.constructor ===A);//true true true
//Something.prototype.constructor is a circular reference as constructor
//references Something
console.log(A.prototype.constructor.prototype.constructor.prototype
.constructor.prototype.constructor === A);//true
Constructor comes with prototype and is set to the constructor function but you can overwrite it (usually done when inheriting so you usually see it repaired after inheriting)
Child.prototype=Parent.prototype;
//Child.prototype.constructor now incorrectly refers to Parent
console.log(Child.prototype.constructor===Parent);//true
//repair constructor
Child.prototype.constructor=Child;
More on inheritance, constructor functions and prototype here.
Since all objects have a prototype (unless created with Object.create(null)) all objects have a constructor property pointing to the function that created them:
console.log([].constructor===Array);
var arr = new [].constructor(1,2,3);//same as new Array(1,2,3)
console.log(arr);//[1,2,3]
//the following temporarily casts the string to String
console.log("hello".constructor===String);//true
//same with numbers
console.log(1..constructor===Number);//true
console.log(function(){}.constructor === Function);//true
Assuming I have something like this:
function A() {}
function B() {}
B.prototype = Object.create(A.prototype);
function C() {}
C.prototype = Object.create(B.prototype);
var inst = new C();
I can now do inst instanceof C == true, inst instanceof B == true, instanceof C == true.
But how could I "iterate" the constructor functions up starting from the instance of C() so that it'd return function C(), function B(), function A() which I could then use to instantiate another instance.
You can iterate the prototypes by doing
for (var o=inst; o!=null; o=Object.getPrototypeOf(o))
console.log(o);
// {}
// C.prototype
// B.prototype
// A.prototype
// Object.prototype
However, that will only iterate the prototype chain. There is no such thing as a "constructor chain". If you want to access the constructors, you will need to set the .constructor property on the prototypes appropriately when inheriting:
function A() {}
function B() {}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
function C() {}
C.prototype = Object.create(B.prototype);
C.prototype.constructor = C;
var inst = new C();
for (var c=inst.constructor; c!=null; (c=Object.getPrototypeOf(c.prototype)) && (c=c.constructor))
console.log(c);
// C
// B
// A
// Object
which I could then use to instantiate another instance
You would only need to know of C for that, not of the "chain". You may access it via inst.constructor if you have set C.prototype.constructor correctly.
However, it might be a bad idea to instantiate objects from arbitrary constructors; you don't know the required parameters. I don't know what you actually want to do, but your request might hint at a design flaw.
Go up the chain using the constructor property of the object's prototype.
For example, after your code:
C.prototype.constructor === A
is true, as is
inst.constructor.prototype.constructor === A
... and so forth.
What is o ?
If I am not mistaken, prototype means that F is going to inherit from o , but that is all I can understand here.
Can someone break this down for me:
if (!Object.create) {
Object.create = (function () {
var F = function(){};
return function (o) {
if (arguments.length !== 1) {
throw new Error('Object.create implementation only accepts one parameter.');
}
F.prototype = o;
return new F();
};
}());
o is a parameter that you pass into the function.
For example:
var myObj = Object.create({
myFn: function(){}
});
Then you can do:
myObj.myFn();
The context of that code can help you understand it better.
This polyfill covers the main use case which is creating a new object for which the prototype has been chosen but doesn't take the second argument into account. - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Polyfill
The code is intended to serve as a replacement for Object.create(proto [, propertiesObject ]) when Object.create is not provided by the environment.
So, o is just the object which will serve as the prototype of the new object you are creating.
In practice, this means that we can use o as our superclass (or more correctly o is the prototype of our superclass).
The example from the Mozilla docs makes this clear:
//subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Answering the comment, this feels a little too long for the comment box:
o is the prototype of the object you want to inherit from. Technically it is an object too, everything in JS is an object. How is almost everything in Javascript an object?.
Why would you want to inherit from another object? What's the point of OOP?
What does this line do? F.prototype = o;
Lets repeat the full code, except with comments:
// if the execution environment doesn't have object.create, e.g. in old IE
if (!Object.create) {
// make object.create equal to something
Object.create = (function(){
// create a new object F which can be inherited from
function F(){}
// return a function which
return function(o){
// throw an error if
if (arguments.length != 1) {
throw new Error('Object.create implementation only accepts one parameter.');
}
// force F to inherit o's methods and attributes
F.prototype = o
// return an instance of F
return new F()
}
})() // this is an IIFE, so the code within is automatically executed and returned to Object.create
}
When making the prototypal inheritance, it's asked to refer the child's constructor back to itself below,
A = function() {}
B = function() {}
B.prototype = new A;
B.prototype.constructor = B;
What would take adverse effect if not?
EDIT
As #GGG & #CMS have explained, the constructor alignment takes no
effect on creating the child object by new Child(...), but is
necessary to correctly reflect the child object's constructor later.
#GGG has also suggested a defensive alternative to extend
the prototype chain. While Child.prototype = new Parent(...)
includes parent's properties to child, Child.prototype =
Object.create(Parent.prototype) doesn't.
First, please don't do this:
B.prototype = new A;
Do this instead (shim Object.create for old browsers):
B.prototype = Object.create(A.prototype);
As for constructor, nothing will break if you don't do this, but if you don't:
A = function() {};
var a = new A();
console.log(a.constructor); // A
B = function() {};
var b = new B();
console.log(b.constructor); // A (!)
...setting the constructor property of the prototype back to the actual constructor function allows you to do this:
B.prototype.constructor = B;
var b = new B();
console.log(b.constructor); // B