Reputation: 2727
I began to like the following pattern (sry, Coffeescript here cause it's more readable in that case):
Parent = (proto)->
self = Object.create proto
public1 = ->
console.log "in public1 with self: ", self
console.log "in public1 with name: ", self.name
self.public1 = public1
self
Child = (proto)->
self = new Parent proto
private1 = ->
console.log "in private1 with self: ", self
console.log "in private1 with name: ", self.name
self.public1()
public2 = ->
console.log "in public2 with self: ", self
console.log "in public2 with name: ", self.name
private1()
self.public2 = public2
self
GrandChild = (proto)->
self = new Child proto
public3 = ->
console.log "in public3 with self", self
console.log "in public3 with name: ", self.name
self.public2()
self.public3 = public3
self
felix = new GrandChild name: "Felix"
felix.public2()
That naive attempt of multiple inheritance works and enables a simple and obviously convenient use of 'self' ... smart when you're coming from other oop languages like I do.
Gotcha: every GrandChild object creates a NEW Child as well as a NEW Parent object, so that memory consumption grows in case many GrandChild objects are created.
Augmenting GrandChild's prototype with Child's and Parent's methods would only reference their methods in a GrandChild object as far as I understood (and save lots of space), but reading up and down I do not find a way to have access to self the way I have with the upper solution.
I know Coffeescript itself provides a class based inheritance system on top of JS's prototypal inheritance. Other libs provide solutions as well. I'd like to simply understand what's going on to pick the right solution depending on the use case.
What if - for example - I would like to put private1 and public2 of Child into a prototype, so that these functions are referenced instead of copied?
Can someone enlighten me at that point?
Upvotes: 0
Views: 250
Reputation: 187034
Gotcha: every GrandChild object creates a NEW Child as well as a NEW Parent object, so that memory consumption grows in case many GrandChild objects are created.
False. What you are doing here, say when you new GrandChild
, is that you instantiate a Parent
and then adorn it with methods from the Child
contructor, and then again from the GrandChild
constructor. It's the same object, from Object.create proto
all the way through the grandchild. In that respect, you aren't littering up your context with dummy object at all.
Augmenting GrandChild's prototype with Child's and Parent's methods would only reference their methods in a GrandChild object as far as I understood (and save lots of space), but reading up and down I do not find a way to have access to self the way I have with the upper solution.
Closure based private methods and prototypes don't usually get along. You can have a lot of flexibility when you do it all in constructors like this, but you lose the advantages of using the prototype (like speed from not redefining functions in new scopes all the time).
I know Coffeescript itself provides a class based inheritance system on top of JS's prototypal inheritance. Other libs provide solutions as well. I'd like to simply understand what's going on to pick the right solution depending on the use case.
It does, and when using coffee script there is no reason not to use it. A lot of thought has gone into it. But again private methods will be tricky. Usually private methods are simply made public but underscore prefixed Foo.prototype._privateMethod
to denote their privateness. If that's not good enough, things start to get funky.
What if - for example - I would like to put private1 and public2 of Child into a prototype, so that these functions are referenced instead of copied?
Public methods can go in the prototype and propogate fine, private not so much. Private is not really a good way to think of things in javascript at all, as it's not supported like other languages. Instead, any value (including functions) that you have access to is either in your current scope via local variables or closure, or it's a property on an object that is in your current scope via local variables or closure.
EDIT:
Lastly, the pattern you have here would be better served without the new
keyword. Since you are creating and returning an arbitrary object, you don't need the JS engine to create one for you. So your code should work if you simply remove the new
entirely from your code here.
Constructor functions have a quirk. When they return an object they return that object instead of the one created via new
. Here you are returning self
which you made yourself via Object.create
. If a constructor function returns a non-object (string, number, function, null) it will actually return this
instead. In coffee script this can be tricky because of implicit returns form functions. And when using coffeescript classes, the constructors never return anything, allowing you to deal with this odd problem.
Upvotes: 1