Reputation: 3
First of all, sorry for my broken English - I am not a native speaker.
Now, on to the problem:
I am learning JavaScript design patterns and while trying to implement a bit more complex example of decorator pattern I realized that I cannot modify methods defined in a constructor, but I can modify methods defined with a prototype.
Can someone please explain to me why is this the case, or if I missed something really important along the way.
This is the code of the pattern:
// Basic constructor with one parameter and test method
var ExampleOne = function (param1) {
this.param1 = param1;
this.test = function () {
console.log('Test One');
}
}
// Adding logParam1 method using prototype
ExampleOne.prototype.logParam1 = function () {
console.log(this.param1);
}
// Adding testTwo method using prototype
ExampleOne.prototype.testTwo = function () {
console.log('Prototype Test');
}
// Creating instance of ExampleOne
var example = new ExampleOne('Parameter One');
// Simple decoration
example.decorate = function() {
console.log('Decoration One');
}
// More complicated decoration
var ExampleTwo = function(param1, param2) {
ExampleOne.call(this, param1);
this.param2 = param2;
}
// Creating separate prototype from original one
ExampleTwo.prototype = Object.create(ExampleOne.prototype);
// Trying to change test (defined in constructor)
ExampleTwo.prototype.test = function () {
console.log('Test Two');
}
// Trying to change logParam1 (defined using prototype)
ExampleTwo.prototype.logParam1 = function () {
console.log(this.param1 + ' ' + this.param2);
}
// Creating instance
var examplee = new ExampleTwo('Test Two', 'Decoration Two');
// Testing
example.test(); // Expecting: Test One, Returns: Test One
example.testTwo(); // Expecting: Prototype Test, Returns: Prototype Test
example.logParam1(); // Expecting: Parameter One, Returns: Parameter One
example.decorate(); // Expecting: Decoration One, Returns: Decoration One
examplee.test(); // Expecting: Test Two, Return: Test One << WHY?
examplee.testTwo(); // Expecting: Prototype Test, Returns: Prototype Test
examplee.logParam1(); // Expecting: Test Two Decoration Two, Returns: Test Two Decoration Two
// examplee.decorate(); // Expecting: error, Returns: error
Thnx.
Upvotes: 0
Views: 63
Reputation: 141877
Properties accessors will always access an object's own properties before working up the prototype chain. In your case the objects have a test property which outputs 'Test 1' and their prototypes have a test property that outputs 'Test 2', but that prototype function can't be accessed directly by obj.test
, since Test 1 comes first in the chain.
You can still access 'Test 2': Object.getPrototypeOf( example ).test();
.
You can also still override the original test, but it needs to be done on a per object basis and not on the prototype:
example.test = function () { console.log('Test Two'); }
Or if you make a subclass you can override it in the constructor:
function ExampleFour ( param ) {
ExampleOne.call( this, param );
var superTest = this.test;
this.test = function () {
console.log( 'In overridden test, about to call Test 1' );
superTest.call( this );
};
}
ExampleFour.prototype = Object.create( ExampleOne.prototype );
Upvotes: 1
Reputation: 2036
function ExampleTwo is calling ExampleOne.call(this, param1);
passing ExampleTwo
as context. So ExampleOne
method this.test
is now pointing your ExampleTwo
.
So each variables calling ExampleTwo
with "new" will have an own property function called test()
. This one will be call before the test()
function of the ExampleTwo prototype. Javascript look for own properties first, if it doesn't find, he follow the prototype chain (ExampleTwo.prototype object in this case).
Upvotes: 3