There must be something I don't understand about the JS object model.
From these resources:
I have gathered what I think, or thought, was an accurate mental representation of the object model. Here it is:
All objects have a property, which the docs refer to as [[Prototype]]
. [[Prototype]]
can be thought of as a reference to the object's parent. More accurately:
The reference to the [parent's] prototype object is copied to the internal
[[Prototype]]
property of the new instance. (source 1)
You can get access to the [[Prototype]]
property of the child with Object.getPrototypeOf(child)
The value returned here will be a reference to the parent's prototype (not its internal [[Prototype]]
property, but its actual prototype)
obj.prototype
is different from the object's internal [[Prototype]]
property. It acts like the blueprints used to make instances of this exact object, while its [[Prototype]]
property points to the blueprints used to make instances of its parent.
Parent.prototype === Object.getPrototypeOf(child); //true
To elaborate:
If you add a function to child.prototype
the function will be available to child
and any of it's children.
If you add a function to parent.prototype
, which is equivalent to adding a function to Object.getPrototypeOf(child)
, then the function will be available to parent
and all of it's children, which includes child
and all of its siblings
.
You can use Object.create()
to create a new object with whatever [[Protoype]]
property you want. So you can use it as a way to implement inheritance. See source 2 for an example.
With this in mind, I wanted to get a working example of my own going. My plan was to create a parent 'class' and then make a child 'class' that inherited from it.
I wanted the child class to implement a method, which overloaded a method from the parent. The caveat is that I want the child's version of the method to call the parent's version of the method and then do some extra stuff.
Here is what I came up with, see below for the issues associated with it:
var Parent = function() {};
Parent.prototype.myF = function() {
console.log('derp');
};
function Child() {
Parent.call(this);
};
//make [[prototype]] of Child be a ref to Parent.prototype
Child.prototype = Object.create(Parent.prototype);
//need to explicitly set the constructor
Child.prototype.constructor = Child;
Child.prototype.myF = function() {
Object.getPrototypeOf(this).myF();
console.log("did I derp??");
};
childInstance = new Child();
childInstance.myF();
It appears to be the case that when I attempt to overload Parent.myF()
, while I am overloading it, I am actually modifying the original function at the same time. This appears to be the case because the logged results are:
'derp'
'did I derp??'
'did I derp??'
presumably the first occurance of 'did I derp??'
is coming from a modified version of the parent's function, which I don't mean to do, then the second version is coming from the child's function.
Can anyone elaborate on why this is happening?
To call a parent's function from a child component, pass the function reference to the child component as a prop. Then you can call that parent's function from the child component like props. parentMethodName(). In the example code, we create a parent component named Parent.
prototype = { myMethod: function(arg) { this.name = arg; } } // child function ChildObject(name) { // call the parent's constructor ParentObject. call(this, name); this. myMethod = function(arg) { // HOW DO I CALL THE PARENT METHOD HERE? // do stuff } } // setup the prototype chain extend(ParentObject, ChildObject);
We can use super. method() in a Child method to call Parent method.
Inheritance concept is to inherit properties from one class to another but not vice versa. But since parent class reference variable points to sub class objects. So it is possible to access child class properties by parent class object if only the down casting is allowed or possible....
Great question, it took a bit of testing and researching to find it out.
I changed your code a little bit to find out which function is called when:
var Parent = function() {};
Parent.prototype.myF = function() {
console.log('derp');
};
function Child() {
Parent.call(this);
this.name = 'Test'; // this is a new test property
};
//make [[prototype]] of Child be a ref to Parent.prototype
Child.prototype = Object.create(Parent.prototype);
//need to explicitly set the constructor
Child.prototype.constructor = Child;
Child.prototype.myF = function() {
console.log(this); // here I want to find out the context, because you use it in the next line
Object.getPrototypeOf(this).myF();
console.log("did I derp??");
};
childInstance = new Child();
childInstance.myF();
You can check out the JSFiddle and try it for yourself: http://jsfiddle.net/Lpxq78bs/
The crucial line in your code is this:
Child.prototype.myF = function() {
Object.getPrototypeOf(this).myF(); // this one
console.log("did I derp??");
};
After doing a console.log(this);
to find out what this
refers to, I saw that it changes between the first and the second output of did I derp??
.
I got the following output:
Object { name: "Test" }
Object { constructor: Child(), myF: window.onload/Child.prototype.myF() }
"derp"
"did I derp??"
"did I derp??"
Since I added a 'name' property to the Child
constructor, it would only be around if I am looking at an instance of Child
, not at its .prototype
.
So the first line of the Output means that the current this
context is indeed the childInstance
. But the second one is neither the childInstance
, nor the Parent.prototype
:
Call (myF
of childInstance
): this
refers to the childInstance
. Object.getPrototypeOf(this).myF();
then looks for the [[Prototype]]
of the childInstance
, which is the Child.prototype
, not the Parent.prototype
.
Output: 'did I derp??'
Call (myF
of Child.prototype
): this
refers to the Child.prototype
, which is the childInstances
[[Prototype]] Property. So the second call of Object.getPrototypeOf(this).myF();
finally returns the Parent.prototype
(sort of). Output: 'did I derp??'
Call (myF
of Parent.prototype
instance created by Object.create
): Finally, the myF
on the parent is called. Output: 'derp'
Since your console.log("did I derp??")
comes after the myF
function call, the output is in reverse order. The following graphic illustrates how the code is traversed:
So your assumption about what Object.getPrototypeOf(this).myF();
refers to, was wrong.
By @LukeP: https://jsfiddle.net/Lpxq78bs/28/
To avoid this confusion, and since you are working with a classical inheritance pattern, you could have a look at ES6 Classes. The following would be a rough example of what you are trying to do:
class Parent {
constructor() {
}
myF() {
console.log('derp');
}
}
class Child extends Parent {
constructor() {
super();
}
myF() {
super.myF();
console.log("did I derp??");
}
}
var childInstance = new Child();
childInstance.myF();
I hope this helps in understanding what happens.
Your code is working as expected , the output you are getting is because of Object.getPrototypeOf
and can be explained by
Step 1 : When you cal childInstance.myF();
then it goes to below code where this
refers to childInstance itself
Child.prototype.myF = function() {
Object.getPrototypeOf(this).myF();
console.log("did I derp??");
};
then Object.getPrototypeOf
returns childInstance.[[Prototype]]
which is Child.prototype
and again call myF
method(leaving second line to printed later after the execution of the method) but next time this
will reference to childInstance.[[Prototype]]
.
Step 2 : In this call this
points to childInstance.[[Prototype]]
( or Child.prototype
object itself)
Child.prototype.myF = function() {
Object.getPrototypeOf(this).myF();
console.log("did I derp??");
};
Now Object.getPrototypeOf
returns childInstance.[[Prototype]].[[Prototype]]
( which is Child.prototype.[[Prototype]]
) which is Parent.prototype
and again call myF method but this time myF method will print derp because myF method of Parent.prototype
is being called. After that, second line will print did i derp.
Step 3 : Then the function comes back to step 1 to execute second line which again prints did i derp
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With