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.
Related
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.
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.
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.
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.
in many books and online tutorial there are examples on passing data to a super-class
constructor via a borrowing method pattern:
var Parent = function(name)
{
this.name = name;
this.my_parent = "parent_property";
this.go = function()
{
alert("GO")
}
}
var Child = function(name)
{
this.name = name;
this.my_child = "child_property";
Parent.call(this);
alert(this.hasOwnProperty("go")) // HERE TRUE!!!
}
var ChildChild = function(name)
{
this.name = name;
this.su = function(){}
}
// PSEUDO CLASSICAL ECMA STANDARD
Child.prototype = new Parent("PARENT");
ChildChild.prototype = new Child("CHILD");
var c = new ChildChild("CHILDCHILD");
now my question is: is this correct? in that pattern the properties of the super-class
are copied into THIS but in a OOP system I think that those properties must be in its
super-class. Now BORROWING constructor is only another pattern to make a sort of inheritance so I could not use prototype and so all the chain superclass properties are
into the last child class...but I don't think it's efficient.
So, at end, how can I pass data to a super-class without that pattern?
Thanks
By calling .call() you don't inherit in the classical sense of the word instead you tell Child to apply Parents prototype onto itself and thus Child.prototype has cloned properties and methods from Parent. This has no issues performance wise whatsoever though so abandoning prototype for efficiency reasons is not a valid reason.
If I can be honest I think enforcing OO paradigms onto javascript is the biggest mistake a javascript developer can make. Much like having to learn to deal with immutability in functional programming trying to make javascript behave like classical OO will only work against you in the long run.
It doesn't answer your question but there's tons of different ways to apply a super functionality to javascript none of which I can recommend though as there's no definitive version that doesn't come with a downside somewhere down the line.
JavaScript has no inherent support for building inheritance hierachies. The JavaScript way of doing type extensions would be to add properties from the 'parent class' to the 'child class', ie
function Parent(foo) {
this.foo = foo;
}
Parent.prototype.sharedFoo = 'sharedFoo';
function Child(foo, bar) {
// call the parent constructor
Parent.call(this, foo);
this.bar = bar;
}
Child.prototype.sharedBar = 'sharedBar';
// copy the properties of the parent class
for(var prop in Parent.prototype) {
if(Parent.prototype.hasOwnProperty(prop))
Child.prototype[prop] = Parent.prototype[prop];
}
It's also easily possible to add true prototypical inheritance, for example like this.
Via use of the clone() function, it's now possible to let the prototype object of the 'child class' inherit from the prototype object of the 'base class':
function Parent(foo) {
this.foo = foo;
}
Parent.prototype.sharedFoo = 'sharedFoo';
function Child(foo, bar) {
// call the parent constructor
Parent.call(this, foo);
this.bar = bar;
}
// inherit from the parent class
Child.prototype = clone(Parent.prototype);
Child.prototype.sharedBar = 'sharedBar';
JavaScript is a prototype based, functional language that pretends to be the cousin of Java.
Here is a few key things about JavasSript:
Everything is an Object, including Functions
Object is more like Hash, it is a collection of key value pairs
prototype itself is Object as well
To answer your first question about performance of "borrowing" prototype:
Typically, a JavaScript class contains a collection of [name, function object] pairs. When you borrow the prototype of the parent class, you basically copy the values of the parent prototype object into child class's prototype object.
The copy is by reference, when the function is copied, the function code is not duplicated, only the reference is copied. This is similar to function pointers in C language.
Thus the only performance hit is the
duplication of the prototype object,
which takes very little memory.
To answer your second question of how to pass data to Parent Class in a clean way:
There are many libraries out there that has some OOP style inheritance already built in. You can roll your own as well, but that would not be trivial.
I recommend a framework called Joose.
It supports classes, inheritance, mixins, traits, method modifiers and more.
Stable and used in production environments.
Elegant, and will save you a lot of key strokes
Using Joose, parent constructors can be overridden
or augmented, and SUPER() or INNER()
methods will be provided to access the
original constructor, or the subclass
constructor.