I come from classes object orientation languages and recently I have been learning those fancy dynamic languages (JavaScript, Python and Lua) and I want some tips about how to use OO in those languages. It would be useful to know the pitfalls and the shortcomings of such approach and the advantages compared to traditional OO.
The general notion that I got is that prototype based OO is basically programming with objects but no standard on how to use them whereas in normal OO there is a fixed predefined way to make and use objects.
In summary, what is the good, the bad and the ugly parts of such approach?
Prototype-based OO lends itself poorly to static type checking, which some might consider a bad or ugly thing. Prototype-based OO does have a standard way of creating new objects, you clone and modify existing objects. You can also build factories, etc.
I think what people like most (the "good") is that prototype-based OO is very lightweight and flexible, offering a very high power-to-weight ratio.
For tips on how to use prototype-based OO, a great place to start is the original Self paper on The Power of Simplicity.
To conserve the bandwidth here is the link to my answer on "How can I emulate “classes” in JavaScript? (with or without a third-party library)". It contains further references as well as examples.
The short answer: the heart of JavaScript's prototypal OO is delegation. In this style of OOP different objects of the same "class" can delegate the handling of methods and properties to the same prototype (usually some third object):
var foo = {
property: 42,
inc: function(){
++this.counter;
},
dec: function(){
--this.counter;
}
};
// Note: foo does not define `counter`.
Let's create a constructor for objects with foo as a prototype. Effectively, everything unhandled will be delegated to foo.
var Bar = function(){
this.counter = 0;
};
Bar.prototype = foo; // This is how we set up the delegation.
// Some people refer to Bar (a constructor function) as "class".
var bar = new Bar();
console.log(bar.counter); // 0 --- Comes from bar itself
console.log(bar.property); // 42 --- Not defined in bar, comes from foo
bar.inc(); // Not defined in bar => delegated to foo
bar.inc();
bar.dec(); // Not defined in bar => delegated to foo
// Note: foo.inc() and foo.dec() are called but this === bar
// that is why bar is modified, not foo.
console.log(bar.counter); // 1 --- Comes from bar itself
Let's define inc()
directly on bar:
bar.inc = function(){
this.counter = 42;
};
bar.inc(); // Defined in bar => calling it directly.
// foo.inc() is not even called.
console.log(bar.counter); // 42 --- Comes from bar
Setting up the single inheritance chain:
var Baz = function(){
this.counter = 99;
};
Baz.protype = new Bar();
var baz = new Baz();
console.log(baz.counter); // 99
baz.inc();
console.log(baz.counter); // 100
console.log(baz instanceof Baz); // true
console.log(baz instanceof Bar); // true
console.log(baz instanceof Object); // true
Neat, eh?
Before worrying about how to emulate class-based inheritance in JavaScript, have a quick read of Prototypal Inheritance in JavaScript.
Classical inheritance is inherently flawed in terms of flexibility, in that we are saying "this object is of this type and no other". Some languages introduce multiple inheritance to alleviate this, but multiple inheritance has its own pitfalls, and so the benefits of pure composition over inheritance (which, in a statically typed language, is a runtime rather than a compile time mechanism) become clear.
Taking the concept of composition to this "pure" level, we can eliminate classical inheritance altogether along with static typing. By composing objects at runtime and using them as blueprints (the prototypal approach), we need never concern ourselves with boxing objects too tightly through inheritance, nor burden ourselves with the issues inherent in multiple inheritance approaches.
So prototypal means much more flexible development of modules.
Of course, it's quite another thing to say it's EASY to develop without static typing. IMO, it is not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With