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
Related
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.
I'm not sure if the title did this justice, but here is what I have...
function A() {};
A.prototype.B = function(){
this.backref = //?? -- should be set to "a"
};
var a = new A(); // specialized factory...
var b = new a.B(); // instantiate an "a" specialized version of B
var zztop = b.backref instanceof A; //would be true
I need to assign backref to the instance "a" that called the B constructor. How can I do this? I've looked through all the properties in Chrome debugger, and am not even sure it is possible. Anyone know how to do this? I need to do this because I need access to variables stored in "a". Or is there a better way to do something similar?
I'm not sure if there's a way to do this just using the properties given to you, but you can always make the backref one of the arguments to the B constructor:
A.prototype.B = function(backref) {
this.backref = backref;
}
var a = new A();
var b = new a.B(a);
Ugly, but it works.
What you are describing is called inheritance. You want object B to inherit the properties of object A.
function A() {
this.length = 3;
}
function B() {
this.height = 5;
}
B.prototype = new A();
B.prototype.constructor = B;
var obj = new B();
obj.height; // returns 5
obj.length; // returns 3
Here's a jsFiddle: http://jsfiddle.net/d6QeT/
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.
I'm trying to understand inheritance in Javascript, but this code (tested in Firebug) doesn't work the way I'm expecting. What am I not understanding about it?
var A = function(v){
this.v = v || 'foo';
}
A.prototype.shout = function(){ alert(this.v); }
var B = function(){};
B.prototype = new A;
var test = new B('bar')
test.shout() // returns 'foo'
What I'm expecting is that when I assign test the property this.v is set to "bar". As far as I understand JS prototypical inheritance setting B's prototype to A's means everything in B is overwritten. I would expect then that it's constructor is overwritten, and that calling new B('bar') would execute A's constructor with the parameter "bar".
If my understanding is incorrect, could someone please correct me. It would also be good to find the solution to what I'm looking to do:
// constructors from above
B.prototype.yell = function(){ alert('hello world'); }
var test1 = new B('bar'), test2 = new B('spam'), test3 = new B('eggs');
...so that the JS objects I'm creating follow a similar inheritance pattern to standard OOP and therefore B would inherit A's constructor and methods.
Edit:
After reading the comments, I believe a better question would be to ask how would one overwrite B's constructor with A's?
Following is a constructor. It runs when you call new A.
var A = function(v){
this.v = v || 'foo';
}
In B constructor is function(){}; So you are not setting this.v
To achieve result you are trying you should follow this pattern:
var A = function(v){
this.v = v || 'foo';
}
A.prototype.shout = function(){ alert(this.v); }
var B = function(v){
B.prototype.constructor.call(this,v); // here you call A constructor
};
B.prototype = new A;
var test = new B('bar')
test.shout() // returns 'bar
When you set
var B = function(){};
you create a parameterless constructor B. Then when you do
B.prototype = new A;
you are calling the A constructor with no parameters (causing this.v = 'foo'), and then causing B's prototype to point to the v and shout from A. However, B as a constructor hasn't changed. This can be seen by adding some parameters to the definition of 'B', for example:
var B = function(x){this.v += x};
should produce 'foobar'.
Addendum:
The closest way I can think of to "copy" the constructor is actually to create both constructors with some third-party function and assign to both A & B. Example:
var objmaker = function(defaultval) {
return function(v) { this.v = v || defaultval; };
}
var A = objmaker('foo');
A.prototype.shout = function(){ alert(this.v); }
var B = objmaker('bar');
B.prototype = A.prototype; // B can now shout()
var testA1 = new A('A');
testA1.shout(); // returns 'A'
var testA2 = new A();
testA2.shout(); // returns default 'foo'
var testB1 = new B('B');
testB1.shout(); // returns 'B'
var testB2 = new B();
testB2.shout(); // returns default 'bar'
It's not really copying, as you can see by the different default values, but it is one way to ensure the two definitions stay in sync.
Instead of setting the prototype to a new instance of A, make B's prototype delegate up to A's prototype. Crockford calls this beget, it's implemented as dojo.delegate in Dojo. It's a simple function that looks like this:
function delegate(o){
F = function(){}
F.prototype = o;
return new F;
}
And you can use it to create this link between prototypes:
var B = function(){}
B.prototype = delegate(A.prototype);
By doing this, the A constructor never gets called, and the v value is never set. This limits inheritance to only the prototype, and not the prototype plus constructor.
Try
var test2 = new A('baz');
test2.shout(); //returns baz
I think when you make 'var B' a new function, rather than making it a' new A', you wipe out the 'constructor' you made 'A' as.
I'm not sure how the original is still getting invoked to set test's instance of v to 'foo'.
How about instead of trying to make javascript work like some other language, you could maybe learn something new from it, and use so it works like javascript?
have a look at this:
http://javascript.crockford.com/prototypal.html