Instantly share code, notes, and snippets.

Embed
What would you like to do?
OLOO (objects linked to other objects) pattern explored (with comparison to the prototype style of the same code)
function Foo(who) {
this.me = who;
}
Foo.prototype.identify = function() {
return "I am " + this.me;
};
function Bar(who) {
Foo.call(this,"Bar:" + who);
}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.constructor = Bar; // "fixes" the delegated `constructor` reference
Bar.prototype.speak = function() {
alert("Hello, " + this.identify() + ".");
};
var b1 = new Bar("b1");
var b2 = new Bar("b2");
b1.speak(); // alerts: "Hello, I am Bar:b1."
b2.speak(); // alerts: "Hello, I am Bar:b2."
// some type introspection
b1 instanceof Bar; // true
b2 instanceof Bar; // true
b1 instanceof Foo; // true
b2 instanceof Foo; // true
Bar.prototype instanceof Foo; // true
Bar.prototype.isPrototypeOf(b1); // true
Bar.prototype.isPrototypeOf(b2); // true
Foo.prototype.isPrototypeOf(b1); // true
Foo.prototype.isPrototypeOf(b2); // true
Foo.prototype.isPrototypeOf(Bar.prototype); // true
Object.getPrototypeOf(b1) === Bar.prototype; // true
Object.getPrototypeOf(b2) === Bar.prototype; // true
Object.getPrototypeOf(Bar.prototype) === Foo.prototype; // true
var Foo = {
Foo: function(who) {
this.me = who;
return this;
},
identify: function() {
return "I am " + this.me;
}
};
var Bar = Object.create(Foo);
Bar.Bar = function(who) {
// "constructors" (aka "initializers") are now in the `[[Prototype]]` chain,
// so `this.Foo(..)` works easily w/o any problems of relative-polymorphism
// or .call(this,..) awkwardness of the implicit "mixin" pattern
this.Foo("Bar:" + who);
return this;
};
Bar.speak = function() {
alert("Hello, " + this.identify() + ".");
};
var b1 = Object.create(Bar).Bar("b1");
var b2 = Object.create(Bar).Bar("b2");
b1.speak(); // alerts: "Hello, I am Bar:b1."
b2.speak(); // alerts: "Hello, I am Bar:b2."
// some type introspection
Bar.isPrototypeOf(b1); // true
Bar.isPrototypeOf(b2); // true
Foo.isPrototypeOf(b1); // true
Foo.isPrototypeOf(b2); // true
Foo.isPrototypeOf(Bar); // true
Object.getPrototypeOf(b1) === Bar; // true
Object.getPrototypeOf(b2) === Bar; // true
Object.getPrototypeOf(Bar) === Foo; // true
@polotek

This comment has been minimized.

Show comment
Hide comment
@polotek

polotek May 15, 2013

My ctor library does almost exactly this. It keeps the constructor pattern but focuses on just creating objects. https://github.com/polotek/ctor

I like the idea in this that Bar is an object that you create from. But the constructor is still an important concept. And the way you suggest tacking it on in the second example seems confusing and forced. Curious to hear what you think of ctor.

polotek commented May 15, 2013

My ctor library does almost exactly this. It keeps the constructor pattern but focuses on just creating objects. https://github.com/polotek/ctor

I like the idea in this that Bar is an object that you create from. But the constructor is still an important concept. And the way you suggest tacking it on in the second example seems confusing and forced. Curious to hear what you think of ctor.

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify Aug 24, 2014

FYI: the whole Foo.Foo and Bar.Bar stuff is totally unnecessary cruft. I usually just call them Foo.init and Bar.init.

Owner

getify commented Aug 24, 2014

FYI: the whole Foo.Foo and Bar.Bar stuff is totally unnecessary cruft. I usually just call them Foo.init and Bar.init.

@Samjin

This comment has been minimized.

Show comment
Hide comment
@Samjin

Samjin Jun 8, 2015

I saw your benchmark between oo vs oloo, it seems like the result says oloo is almost 40% slower in some cases. Do you still prefer to use OLOO instead of OO?
http://jsperf.com/performance-oovsoloo

Samjin commented Jun 8, 2015

I saw your benchmark between oo vs oloo, it seems like the result says oloo is almost 40% slower in some cases. Do you still prefer to use OLOO instead of OO?
http://jsperf.com/performance-oovsoloo

@IPWright83

This comment has been minimized.

Show comment
Hide comment
@IPWright83

IPWright83 Jun 15, 2015

@Samjin I'm not sure that it's going to really make much difference? Compare the # of operations running, these are huge numbers so the actual real affect on the performance of your JavaScript execution is likely to be small compared to the rest of the content on the page.

IPWright83 commented Jun 15, 2015

@Samjin I'm not sure that it's going to really make much difference? Compare the # of operations running, these are huge numbers so the actual real affect on the performance of your JavaScript execution is likely to be small compared to the rest of the content on the page.

@mattiaerre

This comment has been minimized.

Show comment
Hide comment
@mattiaerre

mattiaerre Jul 9, 2015

@getify as a .Net developer that loves JavaScript as well I genuinely believe that this pattern is really cool. It simply doesn't try to force the concept of class into a language that doesn't have it. On the other hand it does enforce the concept of prototype chain. I am definitely trying to use it from now on instead of the prototype pattern. Thank you so much for sharing this.

mattiaerre commented Jul 9, 2015

@getify as a .Net developer that loves JavaScript as well I genuinely believe that this pattern is really cool. It simply doesn't try to force the concept of class into a language that doesn't have it. On the other hand it does enforce the concept of prototype chain. I am definitely trying to use it from now on instead of the prototype pattern. Thank you so much for sharing this.

@danielmeneses

This comment has been minimized.

Show comment
Hide comment
@danielmeneses

danielmeneses Aug 5, 2015

Hi there,

i really like the OLOO approach. I've wrote a tinny polyfill to improve the experience of the OLOO pattern, well at least i think it does and i like to work this way ;). I think this approach allows better readability of the code, it also adds a reference of the parent object for each object created (this.parent) and allows methods to have the same name. Here it goes:

// oloo pattern - my tinny polyfill
Object.prototype.oloo = function(o1, o2){
    if( o1 && o2 && typeof o1 === "object" && typeof o2 === "object"){
        // create new object
        var o0 = Object.create(o1);
        // copy all props to the brand new obj
        for( var key in o2 ){
            if(o2.hasOwnProperty(key)){
                o0[key] = o2[key];
            }
        }
        // set parent reference
        o0.parent = o1;
        return o0;
    }
    return null;
}

var Object1 = {
    name: null,
    init: function(name){
        this.name = name;
        console.log(this.name+" - main");
    }
};

var Object2 = Object.oloo( Object1, {
    middleName: null,
    init: function(name, middelName){
        this.parent.init(name);
        this.middelName = middelName;
        console.log(this.middelName+" - 1");
    }
});

var Object3 = Object.oloo( Object2, {
    lastname: null,
    init: function(name, middleName, lastname){
        this.parent.init(name, middleName);
        this.lastname = lastname;
        console.log( this.lastname +" - 2");
    },
    getFullName: function(){
        return this.name +" "+ this.middelName +" "+ this.lastname;
    }
});
Object3.init("Daniel", "Teles", "Meneses");
console.log( Object3.getFullName() );

danielmeneses commented Aug 5, 2015

Hi there,

i really like the OLOO approach. I've wrote a tinny polyfill to improve the experience of the OLOO pattern, well at least i think it does and i like to work this way ;). I think this approach allows better readability of the code, it also adds a reference of the parent object for each object created (this.parent) and allows methods to have the same name. Here it goes:

// oloo pattern - my tinny polyfill
Object.prototype.oloo = function(o1, o2){
    if( o1 && o2 && typeof o1 === "object" && typeof o2 === "object"){
        // create new object
        var o0 = Object.create(o1);
        // copy all props to the brand new obj
        for( var key in o2 ){
            if(o2.hasOwnProperty(key)){
                o0[key] = o2[key];
            }
        }
        // set parent reference
        o0.parent = o1;
        return o0;
    }
    return null;
}

var Object1 = {
    name: null,
    init: function(name){
        this.name = name;
        console.log(this.name+" - main");
    }
};

var Object2 = Object.oloo( Object1, {
    middleName: null,
    init: function(name, middelName){
        this.parent.init(name);
        this.middelName = middelName;
        console.log(this.middelName+" - 1");
    }
});

var Object3 = Object.oloo( Object2, {
    lastname: null,
    init: function(name, middleName, lastname){
        this.parent.init(name, middleName);
        this.lastname = lastname;
        console.log( this.lastname +" - 2");
    },
    getFullName: function(){
        return this.name +" "+ this.middelName +" "+ this.lastname;
    }
});
Object3.init("Daniel", "Teles", "Meneses");
console.log( Object3.getFullName() );
@mrme44

This comment has been minimized.

Show comment
Hide comment
@mrme44

mrme44 Aug 12, 2015

Won't ES6 make your OOLO pattern obsolete. What do you think of OOLO vs the new ES6 syntax for creating classes.

mrme44 commented Aug 12, 2015

Won't ES6 make your OOLO pattern obsolete. What do you think of OOLO vs the new ES6 syntax for creating classes.

@ivanjuras

This comment has been minimized.

Show comment
Hide comment
@ivanjuras

ivanjuras Aug 16, 2015

it won't because it's still the same thing under the hood. It's just syntax sugar. It's still going to be easier to think about object relationships this way.

ivanjuras commented Aug 16, 2015

it won't because it's still the same thing under the hood. It's just syntax sugar. It's still going to be easier to think about object relationships this way.

@SoundLogic

This comment has been minimized.

Show comment
Hide comment
@SoundLogic

SoundLogic Oct 7, 2015

"Class in JS is not harmless sugar for prototypal OO. Class is a virus that infects everything it touches."

SoundLogic commented Oct 7, 2015

"Class in JS is not harmless sugar for prototypal OO. Class is a virus that infects everything it touches."

@noidexe

This comment has been minimized.

Show comment
Hide comment
@noidexe

noidexe Jan 18, 2016

@mrme44 maybe you're assuming that not having classes is a problem that people are trying to fix with patterns like OLOO and that once you have classes there's no reason to use anything else.
No one cares about classes*, OLOO is just a nice way to work with objects taking advantage of the freedom the language gives you.

  • I guess someone does care about classes since the keyword is coming to ES6 but it's just syntactic sugar. It'll probably be used by people who can't think beyond classical OOP and when it doesn't work according to their expectations they'll just say js sucks.

noidexe commented Jan 18, 2016

@mrme44 maybe you're assuming that not having classes is a problem that people are trying to fix with patterns like OLOO and that once you have classes there's no reason to use anything else.
No one cares about classes*, OLOO is just a nice way to work with objects taking advantage of the freedom the language gives you.

  • I guess someone does care about classes since the keyword is coming to ES6 but it's just syntactic sugar. It'll probably be used by people who can't think beyond classical OOP and when it doesn't work according to their expectations they'll just say js sucks.
@matteoantoci

This comment has been minimized.

Show comment
Hide comment
@matteoantoci

matteoantoci Jun 15, 2016

I agree with @SoundLogic and @noidexe. The main reason to NOT use classes is that they force you to think in terms of hierarchies (fragile base class problem, gorilla banana problem, duplication by necessity problem). Always favour composition over inheritance, in JS is very easy!

See more here: https://medium.com/javascript-scene/javascript-factory-functions-vs-constructor-functions-vs-classes-2f22ceddf33e

matteoantoci commented Jun 15, 2016

I agree with @SoundLogic and @noidexe. The main reason to NOT use classes is that they force you to think in terms of hierarchies (fragile base class problem, gorilla banana problem, duplication by necessity problem). Always favour composition over inheritance, in JS is very easy!

See more here: https://medium.com/javascript-scene/javascript-factory-functions-vs-constructor-functions-vs-classes-2f22ceddf33e

@dagolinuxoid

This comment has been minimized.

Show comment
Hide comment
@dagolinuxoid

dagolinuxoid Jan 29, 2017

It's a shame that JS has this awkward new Constructor pattern. IMO creating an object using this awful method is pale in comparison to straightforward OLOO approach. 'Damn' Crockford has invented Object.create() too late :).

dagolinuxoid commented Jan 29, 2017

It's a shame that JS has this awkward new Constructor pattern. IMO creating an object using this awful method is pale in comparison to straightforward OLOO approach. 'Damn' Crockford has invented Object.create() too late :).

@carsonpowers

This comment has been minimized.

Show comment
Hide comment
@carsonpowers

carsonpowers Jun 3, 2017

This is the future.

carsonpowers commented Jun 3, 2017

This is the future.

@jfbilodeau

This comment has been minimized.

Show comment
Hide comment
@jfbilodeau

jfbilodeau Jun 26, 2017

I really fail to see the advantage of OLOO. Even without ES6, it seems that there's more code, more things to think about and less elegance than 'regular' (ie: ES5) style of inheritance.

For example, how is this:
var b1 = new Bar("b1");
var b2 = new Bar("b2");
worst than this:
var b1 = Object.create(Bar).Bar("b1");
var b2 = Object.create(Bar).Bar("b2");

To me, OLOO achieves the same as 'regular' inheritance in JS but I really fail to see the benefits.

jfbilodeau commented Jun 26, 2017

I really fail to see the advantage of OLOO. Even without ES6, it seems that there's more code, more things to think about and less elegance than 'regular' (ie: ES5) style of inheritance.

For example, how is this:
var b1 = new Bar("b1");
var b2 = new Bar("b2");
worst than this:
var b1 = Object.create(Bar).Bar("b1");
var b2 = Object.create(Bar).Bar("b2");

To me, OLOO achieves the same as 'regular' inheritance in JS but I really fail to see the benefits.

@chumlabs

This comment has been minimized.

Show comment
Hide comment
@chumlabs

chumlabs Jun 26, 2017

This really makes sense. I think the key to understanding the value here is that the OLOO pattern makes use of delegation (something the JS prototype chain is really well-suited for), not inheritance (something that class-based languages use). The prototype chain does not really encourage an inheritance model. The OLOO pattern hints at a mental model that is much easier to reason about in JS. It's just linked objects; objects that can delegate (methods & variables) to other objects linked further up the chain. (no .prototype augmentation, no messy .constructor prop...). Need to initialize variables like a constructor does? create an init() method on the delegate.

chumlabs commented Jun 26, 2017

This really makes sense. I think the key to understanding the value here is that the OLOO pattern makes use of delegation (something the JS prototype chain is really well-suited for), not inheritance (something that class-based languages use). The prototype chain does not really encourage an inheritance model. The OLOO pattern hints at a mental model that is much easier to reason about in JS. It's just linked objects; objects that can delegate (methods & variables) to other objects linked further up the chain. (no .prototype augmentation, no messy .constructor prop...). Need to initialize variables like a constructor does? create an init() method on the delegate.

@jfbilodeau

This comment has been minimized.

Show comment
Hide comment
@jfbilodeau

jfbilodeau Jun 27, 2017

Am I wrong in thinking that the main difference between 'prototype' and OLOO is that in 'prototype, the prototype is duplicated and in OLOO the prototype is linked?

jfbilodeau commented Jun 27, 2017

Am I wrong in thinking that the main difference between 'prototype' and OLOO is that in 'prototype, the prototype is duplicated and in OLOO the prototype is linked?

@GodefroyClair

This comment has been minimized.

Show comment
Hide comment
@GodefroyClair

GodefroyClair Jul 3, 2017

@jfbilodeau :
The main problem when thinking through inheritance pattern while coding in JS is that it is NOT what you are doing when you use the constructor call mecanism (ie Factory function + new) or even when you use the new ES6 keywords like Class, inherits...
The reason is that the real inheritance pattern (the one implemented in java or C++ and the one you have in mind when you are reasoning) relies on copying where as the one implemented in js relies on linking.
So, at some point, you're gonna have problems. For starters, once made, "a copy is forever" whereas a link can get cut...
So it is much better to use OLOO because it doesn't "lie" about the true structure you are reliying on. It makes the "thinking" and "making" converge, it connects the abstract and the concrete.

GodefroyClair commented Jul 3, 2017

@jfbilodeau :
The main problem when thinking through inheritance pattern while coding in JS is that it is NOT what you are doing when you use the constructor call mecanism (ie Factory function + new) or even when you use the new ES6 keywords like Class, inherits...
The reason is that the real inheritance pattern (the one implemented in java or C++ and the one you have in mind when you are reasoning) relies on copying where as the one implemented in js relies on linking.
So, at some point, you're gonna have problems. For starters, once made, "a copy is forever" whereas a link can get cut...
So it is much better to use OLOO because it doesn't "lie" about the true structure you are reliying on. It makes the "thinking" and "making" converge, it connects the abstract and the concrete.

@GeoDoo

This comment has been minimized.

Show comment
Hide comment
@GeoDoo

GeoDoo Dec 12, 2017

@GodefroyClair

The reason is that the real inheritance pattern ... relies on copying where as the one implemented in js relies on linking

Great explanation of the concept! Way to go!

GeoDoo commented Dec 12, 2017

@GodefroyClair

The reason is that the real inheritance pattern ... relies on copying where as the one implemented in js relies on linking

Great explanation of the concept! Way to go!

@immutablelist

This comment has been minimized.

Show comment
Hide comment
@immutablelist

immutablelist Feb 19, 2018

I prefer composition over inheritance. Carrying all the forest doesn't make sense.
The difference is INHERITANCE is when you design your types around what they are and COMPOSITION is when you design your types around what they do.

immutablelist commented Feb 19, 2018

I prefer composition over inheritance. Carrying all the forest doesn't make sense.
The difference is INHERITANCE is when you design your types around what they are and COMPOSITION is when you design your types around what they do.

@blachawk

This comment has been minimized.

Show comment
Hide comment
@blachawk

blachawk Mar 1, 2018

I believe through this practice the key takeaway is Behavior Delegation of objects linking to other objects.

blachawk commented Mar 1, 2018

I believe through this practice the key takeaway is Behavior Delegation of objects linking to other objects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment