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
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
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/
Can anyone explain to me why "b" returns undefined and how I can get around this problem? Why does the "this" scope get lost when I call prototype functions by reference?
MyClass = function(test) {
this.test = test;
}
MyClass.prototype.myfunc = function() {
return this.test;
}
var a = new MyClass('asd').myfunc();
var b = new MyClass('asd').myfunc;
// Returns "asd" correctly
console.log(a)
// Returns undefined??
console.log(b())
=== EDIT / SOLUTION ===
As plalx writes, the correct solution in my case is to use .bind(). So the result looks like this:
MyClass = function(test) {
this.test = test;
}
MyClass.prototype.myfunc = function() {
return this.test;
}
var a = new MyClass('asd').myfunc();
var b = new MyClass('asd'),
bfunc = b.myfunc.bind(b)
// Returns "asd" correctly
console.log(a)
// Also returns "asd" correctly!
console.log(bfunc())
You need to explicitely bind the this value if you want this behaviour.
var c = new MyClass('asd'),
b = c.myfunc.bind(c);
console.log(b());
By default, this will point to the leftSide.ofTheDot(); in an invocation, or simply the object on which the function was called.
Note: Calling b(); is the same as window.b();.
Binding every function to the object instance is possible but rather inefficient because functions will not get shared across instances anymore.
E.g.
function MyClass(someVal) {
var me = this;
me.someVal = someVal;
me.someFn = function () {
return me.someVal;
};
}
The line var b... is a function reference and you're not actually calling the function.
Here you are assigning to a variable a result of myfunc() function.
var a = new MyClass('asd').myfunc();
And here, you are asigning to b variable function reference, rather then runing it, and assign result to variable.
var b = new MyClass('asd').myfunc;
And finaly here:
console.log(b())
You trying to log result of function b and in that case b() isn't defined anywhere, only it is assigned reference to function.
Try this:
console.log(b); // It logs [Function]
But besides that, your question is hard to understand.
P.S. Use semicolons!
I've recently started reading up on OOP javascript and one thing that authors seem to skip over is when an object A has been declared and suddenly I see "A.prototype.constructor =A;
For example,
var A = function(){}; // This is the constructor of "A"
A.prototype.constructor = A;
A.prototype.value = 1;
A.prototype.test = function() { alert(this.value); }
var a = new A(); // create an instance of A
alert(a.value); // => 1
So I run the command in firebug "var A = function(){};"
and then "A.Constructor" Which reveals it's a function. I understand this.
I run the code "A.prototype.constructor = A;" and I thought this changes the A constructor from Function to A.
The constructor property of A has been changed right? Instead when I run "A.constructor" it gives me function () still.
What's the point?
I also see A.constructor.prototype.constructor.prototype.. what is going on?
If A inherit B using A.prototype = new B();, you need to reset the constructor property for the class A using A.prototype.constructor=A;, otherwise instances of A would have a constructor of B.
In your case, A.prototype.constructor === A will return true, so A.prototype.constructor = A did nothing.
You can quickly test out that that additional assignment does absolutely nothing:
var A = function() {};
A.prototype.constructor === A; // true -- why assign then?
Resetting the constructor property only makes sense if you've assigned a new prototype object to the class, overwriting the original constructor:
var A = function() {};
A.prototype = protoObject; // some object with members that you'd like to inherit
A.prototype.constructor = A; // reset constructor
In your case, the author might be blindly doing this as good practice, even in cases where it's not necessary.
This code if often use in JS classic inheritance pattern (the code is from JavaScript Patterns by Stoyan Stefanov):
function inherit(C, P) {
var F = function () {};
F.prototype = P.prototype;
C.prototype = new F();
C.uber = P.prototype;
C.prototype.constructor = C;
}
to assign right constructor to the child class.
In your case it did nothing, since A.prototype.constructor === A before assignment.
You might want to see my answer to similar question:
https://stackoverflow.com/a/19616652/207661
TL;DR: constructor is not an own property of an instance. So to make things look consistent JavaScript interpreter needs to set prototype.constructor to function itself. This feature can be used in functions that operates generically on many different types of objects.
According to MDN, All objects inherit a constructor property from their prototype:
Example 1:
var o = {};
o.constructor === Object; // true
..
Example2:
function Tree() {
}
var theTree = new Tree();
console.log(theTree.constructor === Tree ); // true
At runtime, it does not make any difference based on the value of the constructor property.
However, as the constructor property returns a reference to the Object function that created the instance's prototype, one should reset the constructor property when they assign a new prototype to the Object function.
var Forest = function() {};
Forest.prototype = theTree;
console.log(new Forest().constructor === Tree ); // true
Forest.prototype.constructor = Forest;
console.log(new Forest().constructor === Forest ); // true
https://jsfiddle.net/j1ub9sap/
For details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor
regardless of the wisdom of such a naming scheme, is the following valid?
var F = function() {
this.f1 = function() {}
}
F.f1 = function() {}
// "static" call
var v1 = F.f1();
// prototype call
var f = new F();
var v2 = f.f1();
it seems it should be ok since, for example, var and this variables within an object function do not share the same space.
Yes, that is valid.
In your example, F is a function which you assign a property called f1 which is a function itself. If you were to change the code to read f = new F(), then f is an object which inherits from F's prototype, but they're still two distinct objects.
It is valid.
Like the others have stated, there are no prototype related issues here.
You are attaching 2 propertyes to 2 different objects:
the so called "static" function is attached to the function definition (F)
the so called "public" function is attached to the object returned by the constructor (new F())
So, since F !== new F(), they are 2 different thing with different props.
If you want to make use of the prototypal inheritance, you can consider the following example:
var F = function(){}
// function visible to all of F's instances
F.prototype.f1 = function(){console.log("I'm inherited!");}
// a so called "static" function
F.f1 = function(){console.log("I'm static!");}
var instance1 = new F();
var instance2 = new F();
// function visible only to this instance of F
instance1.f1 = function(){console.log("I'm visible only to this instance of F");}