What OOP in Javascript should look like? - javascript

I was writing a longish piece of code using Jquery and as you all know, what it seemed to be a simple project, when growing in complexity, now is looking like an unmanageable spaghetti with functions and code repeated everywhere. Therefore, I started pouring all the functionality over an objects like this:
function MyObject(container) {
this.container = container
};
Notifications.prototype.featureOne = function (arg1, arg2){
};
Notifications.prototype.featureTwo = function (arg1, arg2, arg3){
};
obj1 = new Notifications($('#container'));
obj1.featureOne('arg1', 'arg2');
obj1.featureOne('arg1', 'arg2', 'arg3');
Obviously, that makes it very simple to know what is going on but I noticed I had some code very similar to another (particularly, an ajax function accepting 2 arguments and another ajax function accepting the same 2 arguments than before plus an additional one). What can I do? Create a new prototype method to create a function to wrap both cases there?.
Another question: What are best practices that you use when dealing with OOP in Javascript?.
Thanks!

Prototypical inheritance works like this. Say you have a "class".
// original "class"
var SomeObject = function( constructorArg1 ) {
this.someProperty = constructorArg1;
};
SomeObject.prototype.method1 = function( arg1, arg2 ) {
// some code
};
Now let's say you want to create a class that inherits method1, but also adds more.
// new "class" which inherits from first "class"
var SomeOtherObject = function( constructorArg1 ) {
this.someProperty = constructorArg1;
};
// inheritance happens here
SomeOtherObject.prototype = new SomeObject();
// must also set the constructor as part of prototypical inheritance
SomeOtherObject.prototype.constructor = SomeOtherObject;
// add a second method to your new "class"
SomeOtherObject.prototype.method2 = function( arg1 ) {
// some code
};
You will see that the system isn't perfect, as it doesn't let you inherit the original constructor, and you cannot call parent class methods if they are overwritten, but all methods added to the prototype of the first "class" are now available in the new "class".
There are about 100 ways you can play with this idea to simulate classical inheritance, and pretty much set it up how you want it to work, with being able to call overwritten parent methods from within the extended class etc. Many methods that simulate classical inheritance don't use the prototypical inheritance at all, and instead just simply copy methods from one prototype to another. You will have to do some searching or experimenting to see what works best for you.

Related

Constructor or Object Inheritance in JavaScript

I am new to JavaScript (started learning it this week). I've completed the CodeCademy course (actually just Objects 1 && 2 parts, rest was boring). I thought I learned prototypal inheritance with constructors, but than I've started watching Douglas Crockford: Advanced JavaScript
Right at the beginning of the video, he mentions 2 types of inheritance, and I've realized, everything I thought I knew, I don't know. So I've started playing with Chrome JavaScript console and tried to do something using both inheritance models.
//create constructor
function MyParent(){
this.name = "joe";
this.sayHi = function(){
console.log(this.name);
}
}
//create child object and inherit from parent
var myChild1 = new MyParent();
myChild1.name
"joe"
myChild1.sayHi()
joe
//add method to MyParent, so it can be accessed from myChild1
MyParent.prototype.sayBye = function(){ console.log("bye");}
myChild1.sayBye()
bye
//create another constructor
function MyParent2(){
this.sayHi = function(){
console.log("hi");
}
}
//make it inherit from MyParent, overwriting sayHi if object is instance of MyParent2
MyParent2.prototype = new MyParent();
//overwrote sayHi
var myChild11 = new MyParent2();
myChild11.sayHi();
hi
//still same as MyParent as its not overwriten in MyParent2
myChild11.name
"joe"
Than I've tried to do the same thing using Object.create:
//create an object
var myParent = {
name : "joe",
sayHi : function(){
console.log(this.name)
}
};
//it works
myParent.sayHi()
joe
//create child object
var myChild = Object.create(myParent);
myChild.sayHi()
joe
//add bye method to myChild
myChild.sayBye = function(){ console.log("bye"); }
myChild.sayBye();
bye
//add bye method to myParent - does not overwrite child's bye
myParent.sayBye = function(){ console.log("bye2"); }
//however adding sayBye2 to parent, becomes available on already created child
myParent.sayBye2 = function(){ console.log("bye2"); }
myChild.sayBye2();
bye2
//but its the parent property
myChild.hasOwnProperty("sayBye2")
false
//could make million objects inherit from each other vertically or horizontally
var myChild2 = Object.create(myChild);
myChild2.name
"joe"
So far, just by first impression, I do like both models, maybe I slightly prefer the latter. It seems to be more expressive and powerful.
I've done some search on the vs. topic, but couldn't find a good article, that would explain pros and cons of each approach (other than latter is supported by newer browsers only, but there is a simple workaround). Rest of the posts I found were just tl: dr; and somewhat boring.
So my question is, which type of inheritance should I go with. Are there any perks associated with either? Any major cons for either? Can you mixin both? (eg. I know you can pass object as argument into new Constructor()))
Thanks
EDIT:
Looking at trick to create Object.create() alternative if browser doesn't support it, I realized how simple the hack is. It is basically creating an empty constructor, assigning parent object as its prototype and returning the built constructor as new object. What a neat hack!
if(typeof Object.create !== "function") { Object.create = function (o) { function F() {}; F.prototype = o; return new F(); }; }
But what are the implications? Any gotchas to be aware of?
Both ways are equally powerful. Some says that you are not a real JavaScript master if you do not embrace the pure prototypal approach, but really everything is still just prototypal inheritance and it's a matter of style.
Personnaly, I prefer using a classical approach and make use of the new keyword together with a constructor function.
Why?
The classical model is very well-know.
I don't have to implement an init function on my objects only to do what a constructor does already. As you probably noticed, the pure prototypal approach leaves you without a constructor so you will have to implement an initialization function (generally called init) if you need to run some initialization logic for newly created objects.
However, I find that the pure prototypal approach is a bit less verbose and might be easier to understand for programmers without a strong background with languages implementing classical inheritance.
By the way, one thing you should avoid with the classical model is to inherit using the new keyword like you are doing above because you are running the parent constructor logic unnecessary and it could potentially have undesirable side-effects.
You should be using Object.create like below:
function A(val) { this.val = val; }
A.prototype.alertVal = function () { alert(this.val); };
function B(val) {
A.call(this, val); //call parent constructor
}
B.prototype = Object.create(A.prototype); //inherit from A
var b = new B('test');
b.alertVal(); //test
At the end, it's all a matter of taste and I respect both ways. Maybe someone else will want to improve this answer with some real advantages/disadvantages, but I cannot find any.
Constructing objects with new was pronounced evil, because you can forget to use it and then whatever properties you add to this will end up added to the global object. For this reason I am in for the second approach.
One other thing I have learnt is that you should not try to apply "classical" OOD to JavaScript. It has its own way that should be understood and it is quite nice in fact. I think most of object programming problems in JavaScript come from attempts to stretch notion of "class" onto JavaScript.

What are the differences between these three patterns of "class" definitions in JavaScript?

Are there any important/subtle/significant differences under the hood when choosing to use one of these four patterns over the others? And, are there any differences between the them when "instantiated" via Object.create() vs the new operator?
1) The pattern that CoffeeScript uses when translating "class" definitions:
Animal = (function() {
function Animal(name) {
this.name = name;
}
Animal.prototype.move = function(meters) {
return alert(this.name + (" moved " + meters + "m."));
};
return Animal;
})();
and
2) The pattern that Knockout seems to promote:
var DifferentAnimal = function(name){
var self = this;
self.name = name;
self.move = function(meters){
return alert(this.name + (" moved " + meters + "m."));
};
}
and
3) a similar, simple pattern I've often seen:
var DifferentAnimalWithClosure = function(name){
var name = name;
var move = function(meters){
};
return {name:name, move:move};
}
and
4) The pattern that Backbone promotes:
var OneMoreAnimal= ClassThatAlreadyExists.extend({
name:'',
move:function(){}
});
Update 1: Changed pattern #2 and added pattern #3 in response to Elias' response // minor formatting
Just to be clear: JS doesn't know of classes, just objects and custom, self-defined constructor functions, but that's besides the point.
To answer your question in short: yes, there are some small and even some fairly large differences between the various ways of creating a new object you're posting here.
CoffeeScript:
This is actually the most clear-cut and traditional way to create your own constructor, but it has been "optimized" in the sense that it's been ready set-up to use (optional) closure variables.
Basically, what this code does, is use an IIFE, to wrap both the constructor definition and the proptotype method assignments in their own, private scope, that returns a reference to the new constructor. It's just clean, simple JS, no different from what you might write yourself.
Knockout:
Now this threw me a little, because to me, at least, the snippet you provide looks either like part of a module pattern, or a power constructor. But since you're not using strict mode, omitting the new would still make for dangerous situations, and since the entire function goes trough the trouble of creating a new instance of DifferentAnimal, only to then construct a second object literal, assigning all properties of DifferentAnimal to that secondary object, I'd say you're missing something. Because, truth be told, omitting the last return {}; statement here, would probably make no difference at all. Plus: as you can see, you're declaring a method (move) in what is, in essence, a constructor. This means that every instance will be assigned its own function object move, rather then getting it from the prototype.
In short: have another close look at where you got this snippet from, and double-check if this is the full version, because if it is, I can only see arguments against this.
Using a variable, defined inside the constructor is simply: a closure, suppose your properties have a distinct initial state, determined by some arguments, passed to that constructor:
function MyConstructor(param)
{
var paramInit = param/2;//or something
this.p = paramInit;//this property can change later on, so:
this.reInit = function()
{//this method HAS to be inside constructor, every instance needs its own method
this.p = paramInit;//var paramInit can't, it's local to this scope
};
}
var foo = new MyConstructor(10);
console.log(foo.p);//5
foo.p = 'hi';
console.log(foo.p);//hi
foo.reInit();
console.log(foo.p);//5
console.log(foo.paramInit);//undefined, not available outside object: it's a pseudo-private property
That's all there is too it, really. When you see ppl using var that = this; or something, that's often to create a reference to the main object that is available anywhere, without having to deal with the headaches of this (what does this reference? What should the method do when applied to an object other than the one it was originally intended for? etcetera...)
Backbone:
Here, we're dealing with another case: extending objects (IE: using methods, properties of either an existing "class" (constructor) or a particular instance) is not the same as simply creating an object.
As you well know, JS objects can be assigned new properties at any given time. Those properties can be removed, too. Sometimes, prototype properties can be redefined on the instance itself (masking the prototypal behaviour) etc... So it all depends on what you want the resulting object (the newly created object, that extends the given instance) to look like: do you want it to take all properties from the instance, or do you want both objects to use the same prototype somewhere down the line?
Both of these things can be achieved by using simple JS, too, but they just take a bit more effort to write yourself. However, if you write, for example:
function Animal(name)
{
this.name = name;
}
Animal.prototype.eat= function()
{
console.log(this.name + ' is eating');
};
That could be deemed the equivalent of writing:
var Animal = Object.extend({name:'',eat:function()
{
console.log(this.name + ' is eating');
}});
A lot shorter, but lacking the constructor.
new vs Object.create
Well, that's an easy one: Object.create just is a lot more powerful that new: you can define prototype methods, properties (including weather or not they are enumerable, writeable etc...) right at the time you need to create an object, instead of having to write a constructor and a prototype, or create an object literal and mess around with all those Object.defineProperty lines.
The downsides: Some people still aren't using ECMA5 compliant browsers (IE8 is still not quite dead). In my experience: it does become quite hard to debug sizeable scripts after a while: though I tend to use power-constructors more than I do regular constructors, I still have them defined at the very top of my script, with distinct, clear and quite descriptive names, whereas object-literals are things I just create "on-the-fly". Using Object.create, I noticed I tend to create objects that are really a little too complex to qualify as actual object literals, as though they are object literals:
//fictional example, old:
var createSomething = (function()
{
var internalMethod = function()
{//method for new object
console.log(this.myProperty || '');
};
return function(basedOn)
{
var prop, returnVal= {};
returnVal.myProperty = new Date();
returnVal.getCreated = internalMethod;//<--shared by all instances, thx to closure
if (!basedOn || !(basedOn instanceof Object))
{//no argument, or argument is not an object:
return returnVal;
}
for (prop in basedOn)
{//extend instance, passed as argument
if (basedOn.hasOwnProperty(prop) && prop !== '_extends')
{
returnVal[prop] = basedOn[prop];
}
}
returnVal._extends = basedOn;//<-- ref as sort-of-prototype
return returnVal;
};
}());
Now this is pretty verbose, but I've got my basic constructor ready, and I can use it to extend an existing instance, too. It might seem less verbose to simply write:
var createSomething = Object.create(someObject, {getCreated:function()
{
console.log(this.myProperty);
},
myProperty:new Date()});
But IMO, this makes it harder on you do keep track of what object is created where (mainly because Object.create is an expression, and will not be hoisted.Ah well, that's far from a conclusive argument of course: both have their pro's and con's: I prefer using module patters, closures and power constructors, if you don't that's just fine.
Hope this cleared up a thing or 2 for you.
The first example puts the move function in the prototype which will be shared between all Animal instances.
The second example creates a new move function for every the animal instance.
The third example generates a Animal class with the move function in the prototype similar to the first example but with allot less code.
(In your example the name is also shared between all instances, which you probably don't want)
Putting the function in the prototype makes instantiating Animals faster, and because of the way JIT engines work even the execution of the function is faster.

Super function when modifying a prototype in javascript

Is there a function like super when you are modifying a prototype in javascript?
There is unfortunately no super keyword or equivalent in ECMAScript. This has been a major source of confusion and difficulty to implement real-life inheritance.
Lot's of people have implemented complex solutions (Prototype library, John Resig, and many others), all these solutions create extra closures, manipulate functions code, use special names that may clash with upcoming standards changes, or other complex tricks. Some of these solutions just do not work if there is more than one level of inheritance ( A > B > C ) because these use some form of "this.super" that always refers to C's and therefore creates an infinite loop if B also attempts to call its super method (which happens in real code).
There exists however a very simple an much more efficient solution that I found and use successfully in my projects, and that works for any levels of inheritance, and does not run any risk of name collision. No closure required, no magic, just simple straightforward JavaScript that works on all browsers, here it is:
// Create base class
Shape = function() {};
// Add method draw() to base class
Shape.prototype.draw = function() {};
// Create new class
Box = function() {};
// Make Box inherit from base class using Douglas Crockford Object.create()
// that is now part of ECMAScript 5 (which is why I recommend it)
Box.prototype = Object.create( Shape.prototype );
// Reset the constructor property erased by the former statement
Box.prototype.constructor = Box;
// Create draw() method for Box that calls it's base class draw() method
Box.prototype.draw = function() {
Shape.prototype.draw.call( this ); // Here you go!
}
The only drawback of this solution is that it is requires to type a few more keystrokes than the other solutions. But because there are no closures involved, there is no unnecessary function calls so it will likely be more efficient than any other solution I have seen so far.
Alternatively, if you want to pass all arguments of draw() to the super class method, you can use this form:
Shape.prototype.draw.apply( this, arguments );
Or if the parameters are known and differ from that of the super class you can use:
Shape.prototype.draw.call( this, param1, param2 );
I hope this helps others :)
Not in the language itself -- but there is no reason you cannot add it when you are creating your class. There is actually a very nice exposition on the way that Coffeescript manages prototypal inheritance by Justin Reidy on his blog
The key part is reproduced here:
var __hasProp = Object.prototype.hasOwnProperty;
function __extends(child, parent) {
for (var key in parent) {
if (__hasProp.call(parent, key)) {
child[key] = parent[key];
}
}
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
}
You will also probably want to read #bobince's introduction to working with classes in JavaScript.
not by default, but if you are looking for a way to do classical inheritance in javascript you could consider using a library like prototype or mootools... or if you don't want to go that route, John Resig, the creator of jQuery provides a really nice light solution:
http://ejohn.org/blog/simple-javascript-inheritance/
It's just important to note that inherited arrays and objects are not copied to instances with this implementation - so if you inherit an array you'll want to redifine its values in the subclasses constructor function (otherwise all instances will share a single array) - I can post an example for you if you want to see, there is also one in the comments of that post.
It's possible to use JavaScript's .caller facility to create a general solution that lets you invoke a superclass' implementation of a function with the same name as the calling function. The basic idea is to use a reference to the calling function, walk up the class hierarchy to find which class actually implements that function, and then go up one more step to get the super class.
See https://gist.github.com/1265237 for an example.
This allows a call to a super function without needing to specify the name of the current class. E.g., if A is a superclass of B, then:
A.prototype.calc = function ( x ) {
return x * 2;
}
B.prototype.calc = function ( x ) {
return this._super( x ) + 1;
}
var b = new B();
b.calc( 3 ); // = 7
The _super implementation in the above gist does more work the first time it's called, but speeds up in subsequent calls. This uses the JavaScript function .caller (and falls back to the older arguments.callee.caller in older browsers). It's widely claimed that callee/caller are slow because they can't be optimized, but "slow" is a relative term. Depending on your use case, this approach might well suffice.

javascript inheritance

I know there is a lot of similar questions are tons of great answers to this. I tried to look at the classical inheritance methods, or those closure methods etc. Somehow I consider they are more or less "hack" methods to me, as it doesn't really what the javascript is designed to do. (Welcome anybody correct me if I am wrong).
OK, as long as it works, I satisfy with the classical inheritance pattern like:
PARENTClass = function (basevar) { do something here; };
PARENTClass.prototype = { a: b, c: d}; // prototype is auto gen
// Inheritance goes here
CHILDClass = function (childvar) { do something; };
CHILDClass.prototype = new PARENTClass(*1); // Actual inheritance to the prototype statement
// Instance
CHILDInstance = new CHILDClass(whatever);
Above is somehow, to my understanding the inheritance of JS. But one scenario I have no idea how to implement, is that what if I want to do some initializing DURING object creation (ie, within constructor), and the new object can be used right away.... My illustration on problem might not be too clear, so let me use the following C# Psuedo to explain what I want to do:
class PARENT {
public PARENT (basevar) { ... }
}
class CHILD : PARENT {
public CHILD (basevar) : PARENT (basevar) // constructor of child, and call parent constructor during construct.
{ ... }
}
For some reason (like init. UI elements), putting them in constructor seems the best way to do. Anyone have idea on how can I do it.
PS: in the *1, I have no idea what I should put there.
PS2: The above situation I DID found the jquery.inherit library can do, I just wonder if not using library can achieve it.
PS3: Or my understanding is wrong. Since javascript is not intended to mimick OOP (that's why i call it hack), what is the "CORRECT" logic to implement this.
It is not a hack as such; JavaScript is a prototyped language, as defined by Wikipedia as where:
..classes are not present, and behavior reuse (known as inheritance in class-based languages) is performed via a process of cloning existing objects that serve as prototypes.
As it says, classes are not used in JavaScript; each object that you create is descended from the JavaScript Object; all objects in JavaScript have the prototype object, and all instances of objects you create 'inherit' methods and properties from their object's prototype object. Take a look at the MDC prototype object reference for more information.
As of this, when you call the line:
CHILDClass.prototype = new PARENTClass();
This allows the CHILDClass object to add methods and properties to its prototype object from the PARENTClass object, which creates an effect similar to the idea of inheritance present in class-based languages. Since the prototype object affects every instance created of that object, this allows the parent object's methods and properties to be present in every instance of your child object.
If you want to call your parent class's constructor in your child class's constructor, you use the JavaScript call function; this allows you to call the parent class's constructor in the context of the child class's constructor, therefore setting the newly prototyped properties in your child class to what they are set as in the parent class.
You also do not need to put anything where you have specified the *1, since that line is merely used to add the methods and properties to the child class's prototype object; however, bear in mind that it calls the parent class's constructor, so if there are any arguments that are fundamental in the operation of the parent class constructor, you should check that these are present so as to avoid JavaScript errors.
You can manually invoke the parent constructor in the subclass constructor like this:
CHILDClass = function (basevar) {
PARENTClass.call(this, basevar);
// do something;
};
The trick here is using the call method, which allows you to invoke a method in the context of a different object. See the documentation of call for more details.
JavaScript has no built-in support for inheritance hierarchies as type extension is supposed to be done via aggregation, ie adding desired functionality directly to the object itself or its prototype if the property is to be shared between instances.
Nevertheless, JS is powerful enough to make implementing other forms of object construction possible, including classical inheritance.
Given a clone function - which is enough to add 'true' prototypical inheritance, and not JavaScript's bastardization thereof - your exampe can be implemented like this:
function ParentClass(baseVar) {
// do stuff
}
// don't overwrite the prototype object if you want to keep `constructor`
// see http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
ParentClass.prototype.a = 'b';
ParentClass.prototype.c = 'd';
function ChildClass(childVar) {
// call the super constructor
ParentClass.call(this, childVar);
}
// don't inherit from a ParentClass instance, but the actual prototype
ChildClass.prototype = clone(ParentClass.prototype);
ChildClass.prototype.e = 'f';
It's also possible to add some syntactic sugar for class-based inheritance - my own implementation can be found here.
The example from above would then read
var ParentClass = Class.extend({
constructor: function(baseVar) {
// do stuff
},
a: 'b',
c: 'd'
});
var ChildClass = ParentClass.extend({
e: 'f'
});
I've got a lightweight javascript OOP wrapper that provides 'Class-like' inheritance where you can override base methods or call base constructors or members.
You define your classes like this:
//Define the 'Cat' class
function Cat(catType, firstName, lastName)
{
//Call the 'Animal' constructor.
Cat.$baseNew.call(this, firstName, lastName);
this.catType = catType;
}
//Extend Animal, and Register the 'Cat' type.
Cat.extend(Animal, { type: 'Cat' }, {
hello: function(text)
{
return "meaoow: " + text;
},
getFullName: function()
{
//Call the base 'Animal' getFullName method.
return this.catType + ": " + Cat.$base.getFullName.call(this);
}
})
//It has a built-in type system that lets you do stuff like:
var cat = new Cat("ginger", "kitty", "kat");
Cat.getType() // "Cat"
cat.getBaseTypesAndSelf() // ["Cat","Animal","Class"]
cat.getType() // "Cat"
cat.isTypeOf(Animal.getType()) // "True"
var dynamicCat = Class.createNew("Cat", ["tab","fat","cat"])
dynamicCat.getBaseTypesAndSelf() // ["Cat","Animal","Class"]
dynamicCat.getFullName() // tab: fat cat
source code available at: Class.js
I also have more details in my blog post about OOP in javascript
Just thought I'd mention some of the issues with the classical pattern you're going for:
Reference vars on the super class(es) will be available as essentially statics on ALL instances. For example, if you have var arr = [1,2,3] in the super, and do instance_1.arr.push(4) instance_2.arr.push(5) ALL of these instances will "see" the changes.
So you solve 1. with Ayman's solution which Zakas calls "Constructor Stealing", but now you call the constructor twice: once for your prototype and once for the constructor stealing. Solution - for your prototype use a helper like inheritPrototype (I showed the whole implementation of this in this post: inheritPrototype method FWIW, this essentially came from a combination of page 181 of Zakas's book and some Crockford study.
No privacy (but then again, you'd need to use something like the Durable Object pattern to get this and that may not be what you want)
Object definition is left "dangling": Solution - put an if statement checking for any of your prototype's functions and then define the prototype with a prototype literal.
I have running examples of all of this on github!!!
It's been just as much of a challenge for me to truly grok both: Zakas and Crockford books on object creation and inheritance. I also needed to try some different JavaScript TDD frameworks. So I decided to create an essay on both TDD Frameworks and JavaScript Object Creation & Inheritance. It has running code and jspec tests! Here's the link:*
My GitHub Open Source Essay/Book

Pseudo-classical vs. "The JavaScript way"

Just finished reading Crockford's "JavaScript: The Good Parts" and I have a question concerning his stance on the psuedo-classical vs. prototypal approaches. Actually I'm not really interested in his stance; I just want to understand his argument so I can establish a stance of my own.
In the book, Crockford seems to infer that constructor functions and "all that jazz" shouldn't be used in JavaScript, he mentions how the 'new' keyword is badly implemented - i.e. non-Constructor functions can be called with the 'new' keyword and vice versa (potentially causing problems).
I thought I understood where he was coming from but I guess I don't.
When I need to create a new module I would normally start of like this:
function MyModule(something) {
this.something = something || {};
}
And then I would add some methods to its prototype:
MyModule.prototype = {
setSomething : function(){},
getSomething : function(){},
doSomething : function(){}
}
I like this model; it means I can create a new instance whenever I need one and it has its own properties and methods:
var foo = new MyModule({option1: 'bar'});
// Foo is an object; I can do anything to it; all methods of the "class"
// are available to this instance.
My question is: How do I achieve the above using an approach more suited to JavaScript? In other words, if "JavaScript" were a person, what would she suggest?
Also: What does Crockford mean when he says a particular design pattern "is more expressive" then another?
See: Is JavaScript's “new” Keyword Considered Harmful?
It's important to remember that Crockford, like so many other JavaScript programmers, first approached the language with an eye toward "fixing" it - making it more like other (so-called "classical") OO languages. So a large amount of structural code was written, libraries and frameworks built, and... then they started to realize that it wasn't really necessary; if you approach JS on its own terms, you can get along just fine.
The prototypal variant for the example you have looks like the following in my understanding:
Object.beget = function (o) { /* Crockfords replacement for the new */ }
var myModule = {
something : null,
getSomething : function () {},
setSomething : function () {},
doSomething : function () {}
};
And then you can do:
var foo = Object.beget(myModule);
foo.something = bar;
UPDATE: You can also use the builder pattern to replace a constructor like this:
var myModuleBuilder = {
buildMyModule : function (something) {
var m = Object.beget(myModule);
m.something = something || {};
return m;
}
}
so then you can do:
var foo = myModuleBuilder.buildMyModule(something);
Your implementation is problematic because you're replacing the entire prototype object, losing the properties of the inherited function prototype and it would also break, or at least make it more difficult, the ability to make use of inheritance later on if you wrote other classes the same way.
A method more suited to Javascript would be:
var MyClass = function (storeThis) {
this.storage = storeThis
}
MyClass.prototype.getStorage = function (){
return this.storage;
}
MyClass.prototype.setStorage = function (newStorage){
this.storage = newStorage;
}
Use it:
var myInstance = new MyClass("sup");
alert("myInstance storage: " + myInstance.getStorage());
myInstance.setStroage("something else");
As for the 'new' keyword and Crawford's problems with it, I can't really answer, because I haven't read the book, but I can see how you could create a new object by calling any function with the new keyword, including functions that are supposed to be methods of a class.
And when someone says something, such as a design pattern, is more 'expressive', he or she generally means that the design pattern is clear and simple to understand as to what it is achieving and how.
Javascript isn't a person so she can't really suggest what you do.
None of the answers above have mentioned the plain-old functional style of inheritance, which I tend to find is the simplest.
function myModuleMaker(someProperty){
var module = {}; //define your new instance manually
module.property = someProperty; //set your properties
module.methodOne = function(someExternalArgument){
//do stuff to module.property, which you can, since you have closure scope access
return module;
}
}
Now to make a new instance:
var newModule = myModuleMaker(someProperty);
You still get all the benefits of pseudoclassical this way, but you suffer the one drawback that you're making a new copy of all your instance's methods every time you instantiate. This is probably only going to matter when you start having many hundreds (or indeed, thousands) of instances, which is a problem most people seldom run into. You're better off with pseudoclassical if you're creating truly enormous data structures or doing hard-core animations with many, many instances of something.
I think it's hard to argue that either method is "bad practice" per se.

Categories

Resources