Reputation: 804
I have a class that is extended by many other classes.
I pass data to through an instances of these classes and they seem to call a 'this' property of the main class and each of them are able to do it, does this mean they have their own 'copy' of this value?
I really want to understand how this all works, how is data passed through the classes and used specifically on each one, Il show the code:
The parent class (just a relevant section of it):
export abstract class EngagementGraphNode {
public endpoint: string;
public id: string;
public name: string;
public x?: number;
public y?: number;
public parent?: EngagementGraphNode;
public children: EngagementGraphNode[] = [];
}
Then I have a class which access some of the properties such as this.children:
export class EngagementProduct extends EngagementGraphNode {
public engagements: Engagement[] = [];
public description: string;
public timelineRows: TimelineRow[] = [];
setProperties(json: IEngagementGraphNode, placeholder: string, color: string) {
}
setChildren(filters: IFilterParams, rebuild: boolean): void {
let list = [];
this.engagements.forEach(engagement => {
const item = this.find(engagement, filters, rebuild);
if (this.matchFilters(engagement, filters) && item) { list.push(item) }
});
this.children = list;
}
Then there are several other classes which also use 'this.children'
I think that each this.children relates to the single variable and ultimate value that is contained within the parent class, which means that each class must be being called at separate times for this to work? as it does work.
Could someone explain that if possible please?
Also It looks like the classes call on eachother to send data when the app is first loaded so the data is 'parsed' through - is this what is happening? Perhaps I need to read some computer science books and understand the nitty gritty of whats going on with how classes are called, their sequences and how the data is assigned to instances and how that works.
Upvotes: 1
Views: 55
Reputation: 1074168
The property belongs to the objct, not the class. The property is available to code in all the classes because the expression this.children
has nothing to do with the classes, it has to do with the object this
refers to and whether it has a property called children
. It does, so the property accessor works.
Let's simplify a little. Suppose you have:
class A {
constructor(answer) {
this.answer = answer;
}
aMethod() {
console.log("aMethod: " + this.answer);
}
}
class B extends A {
bMethod() {
console.log("bMethod: " + this.answer);
}
}
class C extends B {
cMethod() {
console.log("cMethod: " + this.answer);
}
}
const first = new C(42);
first.aMethod(); // 42
first.bMethod(); // 42
first.cMethod(); // 42
There is only one object created by new C(42)
. It has the features (such as methods) of class A
, class B
, and class C
, because it inherits from the prototypes associated with those classes. Once you've created the object (first
), what you have in memory (ignoring several details) looks something like this:
+−−−−−−−−−−−−−−−+ first−−−−−>| (C Object) | +−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−+ | [[Prototype]] >−−−−−−>| C.prototype | | answer: 42 | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−+ | [[Prototype]] >−−>| B.prototype | | cMethod: (function) | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−+ | [[Prototype]] >−−>| A.prototype | | bMethod: (function) | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−+ | [[Prototype]] >−−>(Object.prototype) | aMethod: (function) | +−−−−−−−−−−−−−−−−−−−−−+
When you call a method on it, in the normal case this
refers to the object you called the method on, which has the property answer
on it because the A
constructor put it there. It doesn't matter where that method is defined, this
still refers to that same single object.
How did the A
constructor get called to put answer
there? If you don't write a constructor for a subclass, the JavaScript engine creates one for you that looks like this:
constructor(...args) {
super(...args);
}
B
and C
both have that implicit constructor. So new C(42)
calls C
's constructor with 42
, which calls B
's constructor with 42
, which calls A
's constructor with 42
, which puts it on the object being created via this.answer = answer;
.
If you do write a constructor for a subclass, it has to call super
(and it has to do it before using this
), so one way or another, A
will get called.
To see that the property belongs to the object, let's create two objects rather than one:
class A {
constructor(answer) {
this.answer = answer;
}
aMethod() {
console.log("aMethod: " + this.answer);
}
}
class B extends A {
bMethod() {
console.log("bMethod: " + this.answer);
}
}
class C extends B {
cMethod() {
console.log("cMethod: " + this.answer);
}
}
const first = new C(42);
const second = new C(67);
first.aMethod(); // 42
second.aMethod(); // 67
first.bMethod(); // 42
second.bMethod(); // 67
first.cMethod(); // 42
second.cMethod(); // 67
Now, what's in memory looks like this — the only change is that there's now a second
object.
+−−−−−−−−−−−−−−−+ first−−−−−>| (C Object) | +−−−−−−−−−−−−−−−+ | [[Prototype]] >−−−+ | answer: 42 | | +−−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−−−−−+ +−−>| C.prototype | +−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−+ second−−−−>| (C Object) | | | [[Prototype]] >−−>| B.prototype | +−−−−−−−−−−−−−−−+ | | cMethod: (function) | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−+ | [[Prototype]] > −−+ +−−−−−−−−−−−−−−−−−−−−−+ | [[Prototype]] >−−>| A.prototype | | answer: 67 | | bMethod: (function) | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−+ | [[Prototype]] >−−>(Object.prototype) | aMethod: (function) | +−−−−−−−−−−−−−−−−−−−−−+
Upvotes: 3