Using super methods in Javascript based on Crockford's functional inheritance - javascript

I've been reading the chapter on functional inheritance in Crockford's 'The Good Parts'. In the mammal example he gives I'm a bit confused as to why he uses the superior method to modify the get_name function. Here is the example in question:
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
var mammal = function (spec) {
var that = {};
that.get_name = function () {
return spec.name;
};
that.says = function () {
return spec.saying || '';
};
return that;
};
var myMammal = mammal({
name: 'Herb'
});
var cat = function (spec) {
spec.saying = spec.saying || 'meow';
var that = mammal(spec);
that.purr = function (n) {
var i, s = '';
for (i = 0; i < n; i += 1) {
if (s) {
s += '-';
}
s += 'r';
}
return s;
};
that.get_name = function () {
return that.says() + ' ' + spec.name + ' ' + that.says();
};
return that;
};
Object.method('superior', function (name) {
var that = this,
method = that[name];
return function () {
return method.apply(that, arguments);
};
});
var coolcat = function (spec) {
var that = cat(spec);
var super_get_name = that.superior('get_name');
that.get_name = function (n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
var myCoolCat = coolcat({
name: 'Bix'
});
var name = myCoolCat.get_name(); // 'like meow Bix meow baby'
I'm confused about this because I can replicate the same thing by removing the superior method and just changing coolcat as follows:
var coolcat = function(spec) {
var that = cat(spec);
var super_get_name = that.get_name();
that.get_name = function(n) {
return 'like ' + super_get_name + ' baby';
};
return that;
};
So, I don't understand why Crockford chooses to use the superior method. Is anyone able to explain at all?

The idea here is that this:
var super_get_name = that.superior('get_name');
makes super_get_name into a function that — every time it is called — invokes that's original get_name method. This allows the new get_name to call the old (super-class) get_name.
Now, if the original get_name method will never have any effect other than to return a single value that never changes, then yeah, this is kind of pointless; you can just save that single-value-that-never-changes and then use it in the new get_name. But if the original get_name can actually do things (such as, say, run an AJAX request, or change the styling of an HTML element), or if its return-value can change (say, if there were some corresponding set_name method), then there would be an important difference between what your code does (save the original return-value and use it) and what Crockford's code does (save the original method and invoke it).

The confusion that arises from this chapter of Crockford's book arises as what Crockford describes is "his" preferred pattern for implementing inheritance in JavaScript, which relies on his extending the Function object with the Function.prototype.method (chapter 1.3) which he uses to add methods to the Function object.
The problem addressed in the coolcat example is the need to access the method of the parent type. In 'classical' OO languages like Java this is natural as classes exist in their own right. In JavaScript inheritance is prototypical, you make an object of type mammal and then modify the object to create the type cat or coolcat.
Depending on your design you may add properties and functions or override an 'inherited' function. The problem arises when you override an 'inherited' function, in JavaScript you basically replace the old function with the new function, thereby loosing the older function.
Crockford now needs to do two things:
get the parent's (cat's) get_name method; and
save it in a manner that can be used from within the overridden method.
In this code:
var coolcat = function(spec) {
var that = cat(spec),
super_get_name = that.superior('get_name');
that.get_name = function(n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
He does 1. by calling the superior method to get a function that gets the cat's get_name function;
and he does 2. by saving it to the super_get_name variable within the coolcat function(/object) allowing access to the cat's get_name function before it is overridden (more correctly overwritten) by the coolcat's get_name function.
In my opinion the confusion arises because:
The superior method is named oddly: the 'superior' method is simply a function look up by name method and could be better named, for example as getFunctionByName (you can try this by replacing the string get_name, by purr, the coolcat's get_name will now call purr, just remember to call it as super_get_name(10) otherwise you'll get an empty string back).
Secondly the code and the pattern obfuscates the code by relying on some particular Crockford patterns, and is likely to stresses you out if you attempt to dive into this chapter without having followed the entire book.
I think there is a simpler way to achieve this, one that I think because it is completely localized is easier to understand etc., as in the code below:
var coolcat = function(spec) {
var that = cat(spec);
that.parent_get_name = that.get_name;
that.get_name = function() {
return 'like ' + this.parent_get_name() + ' baby';
};
return that;
};
There are some other oddities for example the argument n in definition of the coolcat get_name function, which I can only assume came from copying the purr function, which would suggest a ghost writer!
Finally, I would suggest that before one reads the book one should listen to his talk on 'JavaScript the good parts'. The talk is absolutely brilliant, much better than the book.

Related

How can I extend a class defined behind a closure in JavaScript?

I have a set of JavaScript "classes" where a base class defines functions that are then shared by an inherited class. It is working, and it is set up like this:
var ThingA = function(name) {
this.name = name;
};
ThingA.prototype = {
sayHi: function() {
alert('Hi, ' + this.name + '!');
}
};
var ThingB = function() {
ThingA.call(this, 'Charlie');
};
ThingB.prototype = new ThingA();
ThingB.prototype.constructor = ThingB;
var instanceOfB = new ThingB();
instanceOfB.sayHi(); // alerts 'Hi, Charlie!'
For reasons that are outside of my control, my company prefers to follow this pattern when writing JavaScript:
SomeClass = function() {
// "Private" functions go here
function somePrivateMethod() {
...
}
return {
// "Public" methods go here
somePublicMethod: function() { ... }
};
}();
Now, this is fine as far as things go, and it works well for many situations. But it is more of a functional style. There is only one "class" instance, and everything is static.
I've been asked to modify my working code to more closely match the style my company prefers. So my question is, there a way to inherit from a class that is wrapped inside a factory class? It would look something like this:
FactoryClassA = function() {
var ThingA = function(name) {
this.name = name;
};
ThingA.prototype = {
sayHi: function() {
alert('Hi, ' + this.name + '!');
}
};
return {
createThingA: function(name) {
return new ThingA(name);
}
};
}();
FactoryClassB = function() {
// Define a ThingB class that inherits from ThingA somehow
return {
createThingB: function() {
return new ThingB();
}
};
}();
var instanceOfB = FactoryClassB.createThingB();
instanceOfB.sayHi(); // should alert 'Hi, Charlie!'
Is there a way to define ThingB wrapped in FactoryClassB that inherits from ThingA wrapped in FactoryClassA? Thanks to this question, I know that I'm not going to be able to do it exactly like this. I am thinking of using a method to extend a given class ... somehow?
This answer seems close, but I'm having trouble figuring out the details of how to modify that example to fit with the specifics of my situation. I am willing to bend my company's usual pattern a little bit, but can I at least get closer to it?
UPDATE 1
In response to Adam's comment to just add a parameter to the factory class, here's where I'm stuck:
ThingB.prototype = new ThingA();
ThingB.prototype.constructor = ThingB;
I can't figure out how to adapt these lines to make it work if I just pass in a parameter to the factory class method.
Below is what (I believe) you're looking for:
FactoryClassA = function() {
var ThingA = function(name) {
this.name = name;
};
ThingA.prototype = {
sayHi: function() {
console.log('Hi, ' + this.name + '!');
}
};
// Add the constructor back to the prototype
// (see explanation below)
ThingA.prototype.constructor = ThingA;
return {
createThingA: function(name) {
return new ThingA(name);
}
};
}();
FactoryClassB = function() {
// Bootstrapping:
// Capture the instance, as we'll need it to set up the prototype
var baseInstance = new FactoryClassA.createThingA();
// Capture the constructor
var baseConstructor = baseInstance.constructor;
// Keep a reference to the base prototype
var baseProto = baseConstructor.prototype;
function ThingB(name) {
// Call base constructor, along with our args
baseConstructor.call(this, name);
};
ThingB.prototype = baseInstance;
ThingB.prototype.constructor = ThingB;
ThingB.prototype.sayHi = function() {
console.log('here I am');
// call the base class `sayHi`
baseProto.sayHi.call(this);
};
return {
createThingB: function(name) {
return new ThingB(name);
}
};
}();
// Testing
var foo = FactoryClassB.createThingB("Indeed");
foo.sayHi();
// Output:
// here I am
// hi indeed
Explanation:
in FactoryClassA, this line is necessary:
ThingA.prototype.constructor = ThingA;
Note that every prototype in JS is automatically created with a reference to its constructor. For example, when you do:
function T(){}
T.prototype already has a property called constructor which points back to T.
However, in your implementation of ThingA, you reset the entire prototype, by doing ThingA.prototype = { ... }. Therefore, you now have lost the reference to its constructor. In 99% of cases it is ok, and won't have any negative side effects (which is probably why most developers tend to forget it). However, in the case of inheritance, it may be necessary.
Now, within FactoryClassB, we need to do some bootstrapping:
var baseInstance = new FactoryClassA.createThingA();
var baseConstructor = baseInstance.constructor;
var baseProto = baseConstructor.prototype;
Observe the last two lines, as they are pivotal to achieving inheritance in this design pattern. First, since ThingA's constructor is accessible via the prototype (ThingA.prototype.constructor = ThingA), then it means that given an instance of ThingA, we can directly retrieve its constructor. Since the constructor is the function itself, and since every function has a reference to its prototype, we can keep a reference of ThingA.prototype with baseConstructor.prototype.
Next is the critical part, where we set up the inheritance chain:
function ThingB(name) {
// Call the base constructor
baseConstructor.call(this, name);
};
ThingB.prototype = baseInstance;
ThingB.prototype.constructor = ThingB;
The last line above is quite important, as it tells the prototype what its constructor is, otherwise it would still point to ThingA.
There you have it - prototypal inheritance.
Side note:
You can probably see how the above can get quite tedious, a little grotesque, and repetitive. Ergo, you might want to consider an inheritance library like Fiber.js which follows the encapsulation pattern you desired (along with some bonuses like mixins and decorators). Disclaimer: I authored the library.

How to create objects that behave like native objects

I am new to JS and fully excited about its capability to behave both as a functional & OO language.
I want to create an object Eg: MyString which behaves like the native String() constructor function.
When I call String('name') on the chrome console, I get 'name'.
When I call var s = new String('sname'); I get an object instance.
Similarly I tried doing the same
function MyString(val){
this.toString1 = function(){ return " " + val; }
return val;
}
When I call MyString('name'), I get 'name'
When I call var ms = new MyString('sname'); I get an object which exposes a toString1() method (just like the native String()'s toString())
My question is:
The MyString constructor function polluted the parent/global scope with a new method toString1() when called like this MyString('name'). I dont want this to happen. How do I create objects like the native?
You can check if your constructor is called with new very easily:
function MyString(val) {
if (this instanceof MyString) { // called with new
this.toString1 = function(){ return " " + val; }
this.name = 'My name is ' + val;
} else { // called without new
return '' + val;
}
}
Usually it's a good idea to set methods common to all your instances on the prototype, but i assume that was not the point of your question.
MyString.prototype.getMyName = function(){ return this.name; }
It looks like you should use prototype :
function MyString(val){
this.val = val;
}
MyString.prototype.toString1 = function(){ return " " + this.val }
var s = new MyString("thing");
console.log(s.toString1()); // logs " thing"
The toString1 isn't attached to the external scope. It's automatically accessible on all instances of MyString. The fact it's attached to the prototype and not to the object avoid the duplication of the function, making it more efficient.
If what you want is to avoid the MyString constructor to pollute the external scope when improperly called without the new operator, the answer, while it's easy, is Don't : Don't protect against flagrantly improper use of your API because it makes your code complex without gain. It's a lost fight anyway, bad coders will always find a way to fail using your code. Using new SomeClass(args) is basic JavaScript programming.
Try this:
MyString = function(name){ this.name = name; }
MyString.prototype.toString = function(){ return " " + this.name; }

Which way to use to define classes in JavaScript

I found different ways that seem to work.
Mostly recommended way in textbooks and the internet:
var Person = function() {
this.age = 23;
}
Tony = new Person();
This also seems to work:
function Person() {
this.age = 23;
}
Tony = new Person();
Is there a difference? And an additional question: Usually you cannot simply leave out parentheses. Here it is possible (new Person instead of new Person()). This is because of using the new keyword, right?
A third odd way that I just tried out looks like this:
function Person() {
return {age: 2};
}
Tony = new Person();
Tony = Person(); // both ways work! It seems that you can leave out 'new' here.
Here I don't get an object with the name of my class, but my property is also accessible and it seems like it was quite similar to both above approaches.
What shall I use and what are the technical differences? Thank you!
JavaScript is a classless language. Classes don't exist, but objects may inherit properties from each other by using prototypes. This means you are not limited to implementing inheritance in a class-like manner. Personally, I like to use a BackboneJS-inspired method (code requires UnderscoreJS):
var BaseObject = function(){}; //Create a function so that we may use the new operator.
//There may be code in the constructor
BaseObject.extend = function(obj) { //Add a static function to the BaseObject to extend it
var base = this; //Save a reference for later
//Create the constructor for the sub object. We need to extend it, so we can't use the base constructor. AFAIK, this is the only way to clone the base constructor, i.e. by creating a new function that calls it
var SubObject = _.extend(function(){
base.apply(this, arguments); //Call base constructor
}, this);
SubObject.prototype= _.extend({}, this.prototype, obj); //Create new prototype that extends the super prototype, but does not overwrite it.
return SubObject; //Return the new constructor + prototype
};
This allows you to do cool class-like stuff like this:
var Car = BaseObject.extend({
speed: 0,
acceleration: 5,
accelerate: function(){
this.speed += this.acceleration;
}
});
var RaceCar = Car.extend({
acceleration: 10,
});
var car = new Car();
var raceCar = new RaceCar();
car.accelerate();
raceCar.accelerate();
if(raceCar.speed > car.speed){
console.log('raceCar won');
}else{
console.log('car won');
}
For more information on inheritance in JavaScript, I strongly recommend reading JavaScript: The Good Parts by Douglas Crockford.
Regarding your examples:
The difference between 1 and 2 is minimal. For more information see this question.
In 3, you are just returning an object literal. The new keyword only has influence on the this keyword within the function, which you are not using, and so using new has no effect. For more information, see this quesion
1 and 2 (var x = function vs function x) are very similar. 3 is a completely different thing.
The difference between 1 and 2 has nothing to do with classes and has been asked before on SO (several times). I think the most complete answer is this one:
https://stackoverflow.com/a/338053/1669279
In short, the first x points to an anonymous function and some debugging tools might have problems with that. The first one is available from the line it was defined on while the second is available in the entire scope. Read the linked answer for details.
The 3rd "solution" is not a class at all. It is simply a function that returns an object (might be called a Factory method).
It is not a good idea to return things from your constructors, especially return this. You should only return things if you want to override the normal process of creating objects (like implementing the singleton pattern for example).
As a side-note, you should always use new when you instantiate a class. Here is what happens when you try to be smart and save characters:
function X () {
return this;
}
console.log(X()); // outputs the window object
The parenthesis after calling the constructor with no parameters are optional, but it is frowned upon to avoid them because it results in slightly more confusing code.
To sum it up, i usually use pattern 1. Pattern 2 is also ok.
One problem with pattern 2 can be this one:
var x = new X(); // works
console.log(x.message); // works, I am X
x.method(); // doesn't work, method hasn't been defined yet
function X() {
this.message = 'I am X';
}
X.prototype.method = function() {
console.log(this.message);
};
this is how i do mine:
;(function (window) {
"use strict";
//-- Private Vars
var opt, obj, rm, Debug;
//-- construtor
function App(requestedMethod) {
//-- set up some vars
if(typeof requestedMethod !== 'undefined') {
rm = requestedMethod;
}
opt = {
rMethod: (typeof rm !== 'undefined') ? (rm != null) ? rm : false : false
}
//-- containe resulable objects
obj = {}
//-- call the init method
this.init();
}
/** Public Methods **/
/**
* The Init method called on every page load
*/
App.prototype.init = function () {
var om = opt.rMethod;
//-- Once all init settings are performed call the requested method if required
if(om) {(typeof App.prototype[om] == 'function') ? App.prototype[om]() : _DB('Call to Method [' + om + '] does not exsist.');}
};
/**
* testmethod
*/
App.prototype.testmethod = function () {
};
/** Private Methods **/
function PrivateMethod(){
}
/**
* A console output that should enable to remain enable js to work in IE
* just incase i forget to remove it when checking on those pesky IE browsers....
*/
function _DB(msg){
if(window.console && window.console.log){
var logDate = new Date();
window.console.log('------------------- ' + logDate + ' ----------------------------------');
window.console.log(msg);
}
};
window.App = App;
})(window);
then call it like:
<script src="ptha/to/your/app.js"></script>
<script>$(function() { new App('testmethod'); });</script>
When the code is loaded the new App() will then run once all page load data has completed
Hope this helps.To get access to it outside add the new to a var
var App = new App('testmethod);
then you can access things like
App.testmethod()...
var Person = function() {
this.age = 23;
}
Person is a variable that contains(is referenced) an anonymous function
function Person() {
this.age = 23;
}
but here you declare a function called "Person"
function Person() {
return {age: 2};
}
and so you declare a function that returns a new static object.
The best way depends on the needs, if you want to declare classes use the second, while to create the modules uses the third. For the first method look here: http://helephant.com/2008/08/23/javascript-anonymous-functions/

Is it possible to create a function with another prototype than Function.prototype?

I am working on a parser combinator library in JavaScript. For that I want to create functions that can be called like any other functions, but also have member functions that can be called in turn to produce output based on the function they are attached to (e.g. combinators).
I can of course add members to functions like this:
//the functions I want to add additional members to
function hello(x) {
return "Hello " + x;
}
function goodbye(x) {
return "Goodbye " + x;
}
//The function I want as a member of the above functions.
//it creates another function based on the function it is
//attached to.
function double() {
var that = this;
return function(x) {
return that(x) + ", " + that(x);
};
}
//I can attach them manually to the function objects:
hello.double = double;
//calling hello.double()('Joe') results in => "Hello Joe, Hello Joe"
goodbye.double = double;
//calling goodbye.double()('Joe') results in => "Goodbye Joe, Goodbye Joe"
I could create a function that augments all my functions with a double member, but I would have to remember to call it every time I create a Hey, Sayonara, etc. function. Also my greeting functions would have all those members each, directly on the function object, for each instance. I would prefer to put them all in one prototype and make this the prototype of all my greeting functions. The following options don't work either:
replacing hello.__proto__ (nonstandard, won't work in all browsers)
modifiying Function.prototype directly (would add those members to all other functions as well, but they do not make sense there - I only want to call double on a set of my own functions)
Is it even possible to give a function object a custom prototype or am I stuck with modifying each function object I create?
Update: I changed the above example to be more similar to the actual problem I am working on. This is about modyfing function objects not normal objects. The final goal is to enable a comfortable syntax for parser combinators, e.g. (much simplified):
//parses one argument
var arg = …
//parses one function name
var name = …
//parses a function call, e.g. foo(x+y, "test", a*2)
var functionCall = name.then(elem("(")).then(arg.repSep(",")).then(")").into(process(…))
I want to be able to add members to a set of functions so, when these members are called, they return new functions based on the function on which they were called. This is to be used for parser combinators / monadic parsers.
Yes, you can, using setPrototypeOf.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf.
function prototype() { }
prototype.double = function() { console.log("double"); };
function myfunc() { }
Object.setPrototypeOf(myfunc, prototype);
myfunc.double();
This is essentially the standardized version of __proto__.
There is no other way to directly create a function with a prototype other than Function.prototype. Consider:
function makeFunc() {
return function x() { };
}
function protofunc { }
protofunc.double = { }...
makeFunc.prototype = protofunc;
new makeFunc()
Unfortunately, by returning a function from the makeFunc constructor, rather than the default this, the makeFunc.prototype is not applied.
Or:
myFunc = Object.create(protofunc, ???);
Normally we think of using Object.create to create an object with a prototype, but in this case, there's no way to specify a function as being the object.
Bottom line: the only alternative is to set the prototype explicitly, which you can do either with __proto__, or setPrototypeOf. This is an ES6 feature. Normal browser support caveats apply. See http://kangax.github.io/compat-table/es6/.
Although I know you asked for a solution without using Function.prototype, I wonder whether you had considered that you can chain conditionally-executing behaviors such that a Function.prototype function like double() will allow a co-existence of different behaviors depending on "class" instance...
// This could also be adapted to itself be on Function.prototype
function chainConditions () {
var args = arguments;
return function () {
for (var i=0, argl = args.length; i < argl; i++) {
var ret = args[i].apply(this, arguments);
if (typeof (ret) !== 'undefined') { // If you want to allow undefined to be returnable, you could instead add this to a try-catch and ignore those which throw exceptions or a certain exception
return ret;
}
}
};
}
Function.prototype.double = function () {
if (this.prototype instanceof Salutation) {
var that = this;
return function(x) {
return that(x) + ", " + that(x);
};
}
};
Function.prototype.double = chainConditions(
function () {
if (this.prototype instanceof Tennis) {
var that = this;
return function(x) {
return that(x) + ", " + that(x);
};
}
},
Function.prototype.double
);
function Salutation () {}
function Hello(x) {
return "Hello " + x;
}
function Goodbye(x) {
return "Goodbye " + x;
}
Goodbye.prototype = new Salutation();
function Tennis () {
}
function TennisPlayer (x) {
return x + ' serve';
}
TennisPlayer.prototype = new Tennis();
alert(TennisPlayer.double()('Forehand')); // Forehand serve, Forehand serve
alert(Goodbye.double()('Yellow Brick Road')); // Goodbye Yellow Brick Road, Goodbye Yellow Brick Road
alert(Hello.double()('Yellow Brick Road')); // does not work as we did not use Hello.prototype = new Salutation();
One should be able to abstract this even further by allowing one function to be used for the class type checking (e.g., grouping all Salutation methods on the Function.prototype together as one type check), and another to accept a list of methods keyed to their conditional behaviors.
While it uses its own API, it is fairly non-obtrusive and can even be made to work with existing methods on the Function.prototype which do not play along by throwing an exception (just be sure to include any pre-existing methods last).
A couple of different options. I think you should be thinking in terms of objects and inheritance instead of functions and globals. In the example above, you are basically implying you want "world" to inherit the set of hello methods. (Or do you want "hello" to inherit "world"?)
You should start by reading this paper here: http://www.crockford.com/javascript/inheritance.html
Here's some simple code that demonstrates inheritance using "prototypal inheritance"
// ---------------
function inherit (obj, base) {
var tmp = function () { };
tmp.prototype = base.prototype;
obj.prototype = new tmp();
obj.prototype.constructor = obj;
};
function HelloSet() {
;
}
HelloSet.prototype.helloA = function() {
return "Hello A " + this.displayName;
};
HelloSet.prototype.helloB = function() {
return "Hello B " + this.displayName;
};
function World(displayName) {
HelloSet.constructor.call(this); // constructor chaining
this.displayName = displayName;
}
inherit(World, HelloSet); // World now has all the methdods of HelloSet
// ---------------
// now let's create some worlds
var earth = new World("Earth");
var mars = new World("Mars");
earth.helloA(); // returns "Hello A Earth"
mars.helloB(); // returns "Hello B Mars"
A short answer to your question would be: Yes.
function Parent() {
// constructor
}
function Child() {
// constructor
}
Child.prototype = new Parent();
Here's how to add methods to your Child class:
Child.prototype.someMethod = function() {
// do something
}
It's been a long time that I've used Javascript in an object-oriented fashion unfortunately, but I believe there are some solutions to make the syntax a little bit clearer.

Is this a good decorator pattern for javascript?

I need some simple objects that could become more complex later, with many different properties, so i thought to decorator pattern.
I made this looking at Crockford's power constructor and object augmentation:
//add property to object
Object.prototype.addProperty = function(name, func){
for(propertyName in this){
if(propertyName == name){
throw new Error(propertyName + " is already defined");
}
}
this[name] = func;
};
//constructor of base object
var BasicConstructor = function(param){
var _privateVar = param;
return{
getPrivateVar: function(){
return _privateVar;
}
};
};
//a simple decorator, adds one private attribute and one privileged method
var simpleDecorator = function(obj, param){
var _privateVar = param;
var privilegedMethod1 = function(){
return "privateVar of decorator is: " + _privateVar;
};
obj.addProperty("privilegedMethod1", privilegedMethod1);
return obj;
}
//a more complex decorator, adds public and private properties
var complexDecorator = function(obj, param1, param2){
//private properties
var _privateVar = param1;
var _privateMethod = function(x){
for(var i=0; i<x; i++){
_privateVar += x;
}
return _privateVar;
};
//public properties
var publicVar = "I'm public";
obj.addProperty("publicVar", publicVar);
var privilegedMethod2 = function(){
return _privateMethod(param2);
};
obj.addProperty("privilegedMethod2", privilegedMethod2);
var publicMethod = function(){
var temp = this.privilegedMethod2();
return "do something: " + temp + " - publicVar is: " + this.publicVar;
};
obj.addProperty("publicMethod", publicMethod);
return obj;
}
//new basic object
var myObj = new BasicConstructor("obj1");
//the basic object will be decorated
var myObj = simpleDecorator(obj, "aParam");
//the basic object will be decorated with other properties
var myObj = complexDecorator(obj, 2, 3);
Is this a good way to have Decorator Pattern in javascript?
Are there other better ways to do this?
There are various implementations of the Decorator pattern in Javascript on Wikipedia and other sites - (1), (2), (3). The pattern is defined as:
the decorator pattern is a design pattern that allows new/additional behaviour to be added to an existing object dynamically.
Object extension is already build into the language itself. Objects can be easily extended, and properties can be added anytime. So why should you have to jump through hoops to achieve this? Shouldn't something like this suffice:
var person = { name: "Jack Bauer" };
// Decorated the object with ability to say a given phrase
person.say = function(phrase) {
alert(phrase);
}
// Using the decorated functionality
person.say("Damn it!");
If you want a method to apply to all objects that were created using this function, then add that method/properties to the function's prototype.
Update: If you have clearly defined pieces of functionality which can be mixed and matched as needed into certain types of objects, then the MooTools approach of extending and mixing in behavior into objects is nicely done. To give an example, consider a UI component that can be resized, dragged around with a handle, and deleted by clicking a tick mark at the top-right corner. You may not want to create each component with these behaviors but define all these behaviors separately each into their own object. And later mix in these behaviors into each type of component as needed.
var Resizable = {
...
};
var Draggable = {
...
};
var Deletable = {
...
};
var someLabel = new Label("Hello World");
// one way to do it
someLabel.implement([Resizable, Draggable, Deletable]);
// another way to do it
someLabel.implement(Resizable);
someLabel.implement(Draggable);
someLabel.implement(Deletable);
It looks better and more intuitive (to me) than doing something like
var awesomeLabel = new Resizable(new Draggable(new Deletable(someLabel)));
because we are still dealing with a label, and not some resizable, or some draggable, or some deletable object. Another small point, but still worth mentioning is that the parentheses start getting unmanageable after 3 or 4 decorators, especially without good IDE support.

Categories