CAPÍTULO III.- RESULTADOS Y DISCUSIÓN
3.1. Análisis y discusión de los resultados
3.1.3 Desarrollo de la propuesta
3.1.3.3. Clasificación de las metodologías
Let's start by creating two different constructor functions and an inheritance relationship between them.
Consider the following two function objects: function BaseType (){ this.baseValue = 2; } BaseType.prototype.getBaseValue = function(){ return this.baseValue; }; function ChildType (){ this.childTypeValue = 50; }
// creating inheritance relationship ChildType.prototype = new BaseType();
ChildType.prototype.getChildTypeValue = function(){ return this.childTypeValue;
};
var childInstance = new ChildType();
console.log(childInstance.getBaseValue()); // displays 2 console.log(childInstance.getChildTypeValue()); // displays 50
In the preceding code, we have created two extremely simple constructor functions. As you can see, we have defined a simple property for each one of them which are methods related to each object. However, we have created these simple methods as properties of the prototype object for each function as opposed to directly creating
If you are familiar with the prototype property, you know that every function has
this property by default. The value of this property is an object that is shared with all the instances that are created using the constructor function.
The advantage of creating methods (properties) on prototype object as opposed to
on the constructor function itself is that by doing so, all the instances that are created using the constructor share these methods. Therefore, these instances do not have to have their own copy of these properties, thus optimizing our code's performance and memory usage.
In the preceding code, in the case of BaseType, we simply augmented the prototype
object of this constructor with a method called getBaseValue, but for ChildType, we
did something a little different.
We first created an instance of BaseType and then we assigned it to ChildType using
the following expression:
ChildType.prototype = new BaseType();
After the above assignment, the ChildType.prototype value becomes an instance of BaseType. This means that this prototype object has access to two properties now, baseValue and getBaseValue.
The end result is that there are two properties that instances of ChildType have
access to but didn't need to create them. When we run the following line of code:
console.log(childInstance.getBaseValue()); //displays 2
The childInstance variable can return the value of the baseValue variable, using getBaseValue method.
Of course, childInstance also has access to its own variable childTypeValue. If we
run the following code, 50 will be displayed.
console.log(childInstance.getChildTypeValue()); // displays 50
Property look up in prototype chaining
Let's examine how ChildInstance gets access to the properties of BaseType in a
little more depth.
When we try to access a property on ChildInstance, behind the scenes, a search is
conducted on the instance itself to see if that property is available. If the property is not found, then the search continues to the prototype object of the ChildInstance
But there is more, the instance of BaseType (which is the value of the prototype
object belonging to ChildType) itself has a prototype object and our ChildType
prototype has a link to this prototype object. That prototype object has a property
called getBaseValue. Since this method has access to the BaseType properties, it can
return the value of baseValue.
You can think of how this lookup is conducted as shown here:
Looking for the property in "ChildType" Looking for the property in "ChildType" prototype Looking for the property in "BaseType" Looking for the property in "BaseType" prototype
As you can see, there is quite a bit of searching taking place in order to find the instance property. Also, keep in mind that if the property was not found in the
prototype of BaseType, the search would have continued to the prototype object of
the parent of all objects in JavaScript, the Object type. Let's talk about how that works.
Remember that every function has a prototype property which its value is an
object. This prototype object itself has a prototype property which its value is the prototype object of the Object type.
That is why, when we call the BaseType.toString method, even though we have
not defined this method on BaseType or its prototype object, the call still succeeds
and produces the string value of the object. The toString method is defined on
the prototype object of Object type, and thus is available to all the children of Object type.
It is very important to keep in mind that the search is ceased and will not continue any further in the chain of protoypes, as soon as the property that the search is
being conducted for is found.
To make it a little more clear, let's modify our ChildType to have a property
(method) called getBaseValue. Doing so will result in what is known as shadowing
(or masking) of this property on BaseType.
So, if we modify the code for ChildType as below:
function ChildType (){ this.childTypeValue = 50; }
ChildType.prototype = new BaseType(); ChildType.prototype.getChildTypeValue = function(){ return this.childTypeValue; }; ChildType.prototype.getBaseValue = function(){ return this.childTypeValue; };
var childInstance = new ChildType();
console.log(childInstance.getBaseValue()); // displays 50
The call to childInstance.getBaseValue will now return the value 50 instead of 2. This is because as soon as the search for the getBaseValue method (property)
finds this method on ChildType, it will not search any further and will execute this
method. This of course, will return the value of the childTypeValue property.
One other thing that we need to keep in mind, is the fact that because of the relationship that has been created among all these reference types, the following instance check will return true for all of them.
console.log(childInstance instanceof Object); // displays true console.log(childInstance instanceof BaseType); // displays true console.log(childInstance instanceof ChildType); // displays true You can use this test to see if one reference type is inheriting properties from another reference type.
While prototype chaining has many advantages and allows us to create inheritance among our base objects and our child objects, it has the disadvantage that any changes to the base object's reference type properties are reflected in all the instances of the child classes. This at times may not be a desirable effect and you need to be aware of it.