

Improving EcmaScript5 OO with sugar - Raynos
http://raynos.org/blog/17/Improving-ES5-OO-with-pd

======
raganwald
“There are multiple similar prototypical OO utilies... All solve the same
problem:”

<http://xkcd.com/927/>

~~~
Raynos
For the record, I didn't write this library because I thought I could do it
better.

I wrote it because I didn't know about these other utilities / tools.

------
mrspeaker
I hope ES.next gets a bunch of the goodness that is outlined in Harmony - this
would mostly eradicate the need for stop-gap libraries like pd, or transpilers
like CoffeeScript.
[http://wiki.ecmascript.org/doku.php?id=harmony:object_litera...](http://wiki.ecmascript.org/doku.php?id=harmony:object_literals)

And being able to do

    
    
        var obj = protoObj <| { ... properties ... }
    

would be fantastic. If I that, and short function syntax then I'd be happy.

~~~
Raynos
You need all three I'm afraid.

We need an easy way to mixin/extend objects.

    
    
       var obj = protoObj <| mixin({ ... properties ... }, mixinA);
    

We also need a solid way to create instances.

    
    
       object.create(obj);
       obj.constructor();
    

is just too verbose. There is some talk around making `new` work with object
exemplars which would be great.

------
Autre
Maybe I overlooked, but is there support for "super.method()" or something
along those lines?

~~~
Raynos
super is a nightmare to emulate and get "right". It has a bunch of weird edge
cases you don't really want to think about.

I promote code like

    
    
        var Cat = Object.make(Animal, {
          constructor: function() {
            Animal.constructor.apply(this, arguments);
            ...
          },
          walk: function() {
            Animal.walk.apply(this, arguments);
            ...
          }
        });
    

Now compare:

\- Animal.walk.apply(this, arguments);

\- this.super.apply(this, arguments);

\- this.super.walk.apply(this, arguments);

Using super doesn't fix verbosity, it only fixes hard coupling of Child class
name to Super class name.

For the complexities, edge cases and performance penalties a super
implementation gives, it's simply not worth fixing this hard coupling.

If you know of a super implementation that _just works_ please [Leave an
answer on StackOverflow]([http://stackoverflow.com/questions/8032566/emulate-
super-in-...](http://stackoverflow.com/questions/8032566/emulate-super-in-
javascript))

~~~
glenjamin
I've been getting along fine with nothing but util.inherits from NodeJS.

Are there any real advantages to the "set the prototype to this object"
approach versus building it up by assigment?

    
    
        function Animal(legs) {
            this.legs = legs;
        }
        Animal.prototype.speed = function() {
            return legs * 10;
        }
        
        util.inherits(Dog, Animal);
        function Dog(name) {
            this.constructor.super_.call(this, 4);
            this.name = name;
        }
        
        Dog.prototype.speed = function() {
            // I don't disagree that more sugar here would be good
            return this.constructor.super_.prototype.speed.call(this) * 2;
        }

~~~
Raynos
What your showing is ES3 OO sugar.

The problem I have is that the notion of a constructor function goes against
prototypical OO.

In prototypical OO we just have objects and objects inherit from objects.
there is no notion of a constructor function.

Also note that pd.make returns an object rather then a function.

It's simply a programming style I like, to think of my "class" object not as
the constructor function but as the prototype object.

Not to mention that `x.prototype.foo = ...` is ugly.

    
    
        var Animal = {
            constructor: function () {
                this.legs = legs; 
            },
            speed: function () {
                return this.legs * 10;    
            }
        };
        
        var Dog = pd.make(Animal, {
            constructor: function (name) {
                Animal.constructor.call(this, 4);
                this.name = name;
            },
            speed: function () {
                return Animal.speed.call(this) * 2;    
            }
        });

