Skip to content

Instantly share code, notes, and snippets.

@getify
Last active January 7, 2024 11:58
Show Gist options
  • Save getify/5572383 to your computer and use it in GitHub Desktop.
Save getify/5572383 to your computer and use it in GitHub Desktop.
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
@GeoDoo
Copy link

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!

@tnguven
Copy link

tnguven 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
Copy link

blachawk commented Mar 1, 2018

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

@BenceSzalai
Copy link

OLOO for the win. Also add this to Foo:

  [Symbol.hasInstance](instance) {
    return this.isPrototypeOf(instance)
  }

so this will work fine too:

b1 instanceof Bar; // true
b2 instanceof Bar; // true
b1 instanceof Foo; // true
b2 instanceof Foo; // true

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