Look at Figure 01. The function CONSTRUCT is the equivalent of a C++ constructor. Please note the following
If you look at figure Figure 01 you will notice that the javascript code has identical output to that of the C++ code in , except for the order of construction. To understand why, and to get the same order as in C++, you need to know the steps of construction. Look at the figure below. Given a class 'C', which extends class 'B', which itself extends class 'A', as an example, construction of an instance of C follows the following steps:
Consider the following code and output:
crx_registerClass("ClassA",
{
"VERBOSE": 1,
"public CONSTRUCT": function(pA)
{
console.log("CONSTRUCTING ClassA using pA = " + pA);
}
});
crx_registerClass("ClassB",
{
"VERBOSE": 1,
"extends": "ClassA",
"public CONSTRUCT": function(pA)
{
console.log("CONSTRUCTING ClassB using pA = " + pA);
}
});
crx_registerClass("ClassC",
{
"VERBOSE": 1,
"extends": "ClassB",
"public CONSTRUCT": function(pA)
{
console.log("CONSTRUCTING ClassC using pA = " + pA);
}
});
crx_new("ClassC", 5);
Let us follow what happened:
Hence to make the constructor of ClassB execute its useful code before that of the constructor of ClassC, we call it as the first line of code in the constructor of ClassC. Changing the code of ClassC to the following:
crx_registerClass("ClassA",
{
.
.
.
crx_registerClass("ClassC",
{
"VERBOSE": 1,
"extends": "ClassB",
"public CONSTRUCT": function(pA)
{
this.PARENT.CONSTRUCT(pA);
console.log("CONSTRUCTING ClassC using pA = " + pA);
}
});
crx_new("ClassC", 5);
Let us follow what happened:
We are now almost there towards getting the order of construction that we want but not yet. However, one very important thing to notice is that the ancestors of ClassC fully finished executing their constructors before ClassC finished its own. This is important because it is sufficient in practice. If you are the developer of ClassC, and you want the ancestor's constructor to be called first, all you care about is the ancestors of ClassC to finish doing what they need in their constructors before your class begins executing its constructing code. The order of the construction of your ancestors would matter not. If it did, it would have been the worry of the developer of ClassB, and so forth.
We shall now do the same in ClassB, and call the constructor of Class A as the first line:
crx_registerClass("ClassA",
{
.
.
.
crx_registerClass("ClassB",
{
"VERBOSE": 1,
"extends": "ClassA",
"public CONSTRUCT": function(pA)
{
this.PARENT.CONSTRUCT(pA)
console.log("CONSTRUCTING ClassB using pA = " + pA);
}
});
crx_registerClass("ClassC",
{
"VERBOSE": 1,
"extends": "ClassB",
"public CONSTRUCT": function(pA)
{
this.PARENT.CONSTRUCT(pA);
console.log("CONSTRUCTING ClassC using pA = " + pA);
}
});
crx_new("ClassC", 5);
We now have the effect we usually want. Let us follow what happened:
Often you do not want to define a constructor, but are forced to because the constructor of the class that your class is extending takes parameters, and so you define your constructor such as it forwards those paramaters to the constructor of the class being extended. Starting with CrxOop v1.6, you can use the value 1 for the constructor, and this will create a constructor that will do just that.
crx_registerClass("ClassA",
{
"VERBOSE": 1,
"public CONSTRUCT": function(pA)
{
console.log("CONSTRUCTING using pA = " + pA);
}
});
crx_registerClass("ClassB1",
{
"VERBOSE": 1,
"extends": "ClassA"
});
crx_registerClass("ClassB2",
{
"VERBOSE": 1,
"extends": "ClassA",
"public CONSTRUCT": 1
});
console.log('Creating Instance of ClassB1:');
crx_new("ClassB1", 5);
console.log('Creating Instance of ClassB2:');
crx_new("ClassB2", 5);