Skip to content

Instantly share code, notes, and snippets.

@matthewrobb
Forked from getify/1.md
Created November 30, 2012 18:07
Show Gist options
  • Save matthewrobb/4177454 to your computer and use it in GitHub Desktop.
Save matthewrobb/4177454 to your computer and use it in GitHub Desktop.
rethink how javascript "inheritance" ACTUALLY works...

JavaScript does not have "inheritance" or "prototypal inheritance" or "classes" or any of that jazz... what you've been told, and how you've been taught about it, are a misunderstanding... all this nonsense about constructor functions and new and such... that's all hogwash... well, it's all unnecessary effort, at best.

"Instead... only try to realize the truth... there is no spoon."

What JavaScript does have is "behavior delegation"... and object linking through the "prototype chain"... you merely link two instances of objects together, say Foo and Baz, and say that Baz "delegates" to Foo for any behavior that Baz doesn't own itself but that Foo does own. And thus, any object b (aka, "b is an instance of Baz" in the more confusing terminology) which is linked to Baz, delegates first to Baz, and then to Foo, for behavior.

That's it. Seriously. And function constructors and new and all that stuff, everything you've read before about OO in JS, they're just distractions that lead you to the wrong mental model. And so is the new class cruft (aka "sugar") that's coming in ES6. What's actually useful is the semantics of Object.create() actually exposing how this stuff really works.

See what I mean below, comparing "2.js" (the old school and more confusing way) and "3.js" (the cleaner and "object linking and behavior delegation" way). They both do the same thing. But the latter actually says what it means, while the former masquerades as something it's not.

// "class Foo"
function Foo() {
this.bar = "bar";
}
Foo.prototype.out = function() {
console.log(this.bar);
};
// "class Baz"
function Baz() {
this.baz = "baz";
}
Baz.prototype = new Foo();
Baz.prototype.yes = function() {
this.out();
console.log(this.baz);
};
var b = new Baz();
b.yes(); // "bar" "baz"
// "class Foo"
var Foo = Object.create(null);
Foo.bar = "bar";
Foo.out = function() {
console.log(this.bar);
};
// "class Baz"
var Baz = Object.create(Foo);
Baz.baz = "baz";
Baz.yes = function() {
this.out();
console.log(this.baz);
};
// instead of `var b = new Baz()`
var b = Object.create(Baz);
b.yes(); // "bar" "baz"
// "class Foo"
class Foo {
constructor() {
this.bar = "bar";
}
out() {
console.log(this.bar);
}
}
// "class Baz"
class Baz extends Foo {
constructor() {
this.baz = "baz";
}
yes() {
this.out();
console.log(this.baz);
}
}
var b = new Baz();
b.yes(); // "bar" "baz"
@matthewrobb
Copy link
Author

I added an example using ES6 class syntax and while it may add to the confusion and mislead people on what exactly the paradigm definition is I definitely think it is easier to read/write/maintain.

@getify
Copy link

getify commented Dec 5, 2012

yeah what i hate about the new ES6 class syntax is that it moves us further from understanding what's actually going on. It makes it seem like Foo and Baz in this example are abstract entities that need to get instantiated. That's the wrong mental model. They are actually real proper objects, linked to each other via their [[Prototype]] chain, and when b is created, it's not instantiating some class entity, but just creating another object and adding to the chain.

For years, people didn't understand that .prototype.blah type behavior was actually doing "event delegation", and they kept trying to think of it as static inheritance (c++ style), and then being surprised when the "child-effects-the-parent" kind of behavior comes into play, and calling that a design flaw.

Then, for a brief couple of years here, we've had a new mental model, that of Object.create(..), which actually makes complete and total semantic matching sense with what's really happening. The only problem is not enough people have embraced it and explained it that way.

NOW, we're regressing back to bad semantics, to shut up some of the vocal java-in-javascript crowd, by introducing ES6 classes. It's going to set back the language I think. It we just retrained everyone to think like "3.js", it makes total and complete sense and it actually works.

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