Created
May 10, 2013 04:25
-
-
Save jeremyckahn/5552373 to your computer and use it in GitHub Desktop.
Proxy-based inheritance pattern in JavaScript.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function inherit (child, parent) { | |
function proxy () {}; | |
proxy.prototype = parent.prototype; | |
child.prototype = new proxy(); | |
}; | |
function Parent () {} | |
function Child () {} | |
inherit(Child, Parent); | |
var child = new Child(); | |
console.log(child instanceof Child); // true | |
console.log(child instanceof Parent); // true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@Alxandr
Sorry but it's your post that is "terribly faulty". Let me address several things:
Either you have no experience (that you recall the details of) with true OO languages, or you completely missed the fact that my point was how the prototype system in JS is strange compared to those true OO languages, not strange compared to other prototype systems. I'm frankly not sure which is causing you to get this wrong, but you did miss the point, nonetheless.
In true OO languages, if I declare some protected member properties in a parent class, and then a child class inherits from that parent class, when you instantiate that child class, each child instance _will get its own copy_ of those member properties. AFAIK, in those languages, the only way to create "shared state" is to actually make static properties on a class. You can't accidentally do so in those languages.
Because of that fact, if you're from one of those languages, you're at least somewhat likely to first try to put some properties into a parent "class" (aka
Dad
) and thus assume that when your child "class" (akaSon
) "inherits" from it, the child class (and indeed, all child instances) will get its own copy of those members.Now, _I obviously know_ that this is faulty reasoning (ie, it won't work that way in JS), and that only member methods and shared member properties should go on the parent prototype, whereas non-shared member properties must always go on a
this
instance. It's a learnable fact, and once you do, JS's mechanism is tenable to use._But a new JS dev_ coming from a traditional class-oriented language is highly likely to miss (or be confused by) this difference, and many many many have. The proof is in google and stackoverflow history for the last decade+. A newbie JS dev writing my above snippet is doing so in good faith but is nonetheless going to trip over the problem quickly.
That's exactly what I meant in my previous post when I said:
I suppose you missed that intended meaning?
Ummm, no, that's not how JS works. _Accessing_ a property via
[[Prototype]]
doesn't do any copying... if you try to set a property, then it will be set directly on the instance, which can look like copying, but it's not really copying, it's called "shadowing". In either case, it only happens when you try to set, not when you try to access.Ummm, no. Try it again. The
console.log('my leg is broken: ' + me.brokenLeg); // no legs broken ofcause
has no impact on the howconsole.log('my leg is broken: ' + me.brokenLeg);
works.In fact, your code snippet is quite subtlely confused. What does the copying of
brokenLeg
property is thebreak()
method, because it saysthis.brokenLeg = ...
. When you callmydad.break()
,mydad.brokenLeg
now exists, where before it didn't exist and was instead delegating tomydad.__proto__.brokenLeg
(akaDad.prototype.brokenLeg
). Whenmydad.brokenLeg
property is created, he's now "shadowing"mydad.__proto__.brokenLeg
.So, after the call to
break()
, now you've switched to where you're confusingly comparing a shadowed owned propertymydad.brokenLeg
(which has been specifically set totrue
) with a delegatedme.brokenLeg
which of course is actually still delegating tome.__proto__.__proto__.brokenLeg
(akaDad.prototype.brokenLeg
).FWIW, that's the opposite of what you claimed about
me.brokenLeg
.With all due respect, it appears your misunderstandings on this topic are somewhat of supporting proof of my overall point, that this stuff isn't terribly self-obvious and confuses lots (maybe most?) devs.
Yeah, duh.
But that wasn't the point of my previous code snippet. Again, to repeat myself, the point of my code was that a newbie JS dev would assume that, like in their previous real-OO language, those members on the parent class would end up automatically instance-specific.
It's not until later, when they run into all these gotchas, and learn the hard way, that they "get" it. So thanks again for pointing out what _we all_ (or most of us, anyway) _already knew_ but failing to address _what someone new expects_ when they first arrive at JS and hear about "classes" and think they work like classes work in traditional OO languages.
BTW, there are definitely uses for shared properties on the
Dad.prototype
. For example:In this case, it's clear that neither
Son.prototype
norme
objects need a copy ofDad.prototype.name
, because it's perfectly sensible to delegate up the[[Prototype]]
chain forlastName
. Side note: of course, once a theoreticalDaughter
instance likemysister
gets married, she's then gonna need her own copy oflastName
so it can change if she wants, but until then, it's fine to delegate as another ofmydad
's children.This is an extremely common claim but is nevertheless misguided. Rather that re-count the explanation for the super important difference between simplicity/complexity and ease/difficulty, I'll just point you at the definitive argument: Rich Hickey's "Simple Made Easy" talk. No sarcasm. Seriously, go watch it. It was a ground-breaking, transformative talk when I heard it at Strange Loop a couple of years back.