{
author: createAuthor(),
posts: createPosts()
}
How is that different from this? Object.assign({}, author, post)
In both cases you end up with an object that has an instance of an author and a post. What am I missing?But you don't; not even close.
The first one is a has-a relationship; the object contains two references (`author` and `posts`), which presumably point to an instance of the Author class and a collection of instances of the Post class (or whatever). This is composition.
The second is an is-a relationship; the object has the properties of the author and post objects copied over the top of it. There is now only one object (not three), and if we're lucky, it implements the interface contracts of both the Author class and the Post class.
Consider if Author has a title field that contains their preferred prefix (Mr, Ms, Mrs, Dr), and Post has a title field that contains the subject line.
With the first approach, we could do `foo.author.title` or `foo.posts[0].title`, using our references to the underlying Author or Post instances.
With the second approach, we can do `foo.title` or...`foo.title`. Whups. We have no references, there is no underlying Author or Post instances; there's just a single object which is trying to inherit the behaviour of both the Author and the Post class, and failing.
It's not a horrible way of implementing multiple inheritance in JS, but it's still inheritance. And in it's single inheritance form (`Object.assign({}, author)`) it's yields an identical result to normal prototypal inheritance or the class keyword.
Edit: This becomes even clearer when you start to flesh out the examples. Eg, https://jsbin.com/kigewonepe/1/edit?js,console
Note how obj2 has a `fullName` method (which only Author's do), because it is an author. Except note that it returns the wrong string when you run it, because obj is also a post. Where obj1 works correctly because it has an author and it has a post, without trying to be either of them. Composition over inheritance, just like the Gang of Four said. :)
Object.assign({}, { author: author }, { post: post });
Can you give a better example of where a reference to an instance is any different than copying an instance?EDIT: I fixed your example. https://jsbin.com/zamuqoropa/1/edit?js,console
EDIT 2: In fact, my Object.assign does exactly the same thing as your example of composition. And
console.log(obj1.author === obj2.author);
produces 'true'.https://jsbin.com/vafudizumo/1/edit?js,console
Either you're doing composition wrong, or I'm not doing inheritance like you are claiming.
Object.assign({}, { author: author }, { post: post });
Yep, that's composition and it's identical to my composition example. Of course, you're not actually using Object.assign() to do anything; your code is 100% identical to just saying: {author, post};
Not that there's anything wrong with that...but do note that it's also the exact opposite of what Elliott is advocating for, not what he shows off in his code examples, not what his Stampit library does, etc.> Either you're doing composition wrong, or I'm not doing inheritance like you are claiming.
Your first example (and Elliott's examples) are inheritance. Your second example is composition. The difference is enormous.
Edit: Elliott says here[0]
"Similarly, you can use `Object.assign()` to compose any number of objects together with last-in priority:"
let ninjamouse = Object.assign({}, mouse, ninja);
1) That's not composition, that's inheritance.2) That's the same as your first example, but fundamentally different than your second.
He's trying to make a "ninjamouse" which has the properties and methods of both mice and ninjas, because it is a mouse and a ninja. (That's inheritance, and it's fragile for all the reasons inheritance is always fragile).
Your second example makes an object that has both a mouse and a ninja. That's composition.
"This technique is called concatenative inheritance"
By absolutely no one ever. :)
[0]: https://medium.com/javascript-scene/common-misconceptions-ab...
"By absolutely no one ever. :)" Actually, quite often. A few examples below:
https://en.wikipedia.org/wiki/Prototype-based_programming#Co...
http://aaditmshah.github.io/why-prototypal-inheritance-matte...
http://www.datchley.name/understanding-prototypes-delegation...
Wikipedia disagrees; do you have a citation in mind?
> Which is similar to class based inheritance, but can happen at run time.
That's not a distinguishing feature of class based inheritance; many implementation do this. Python's class based inheritance is extremely flexible and absolutely allows run time modification; to a greater or lesser extent this is true of many dynamic language (Ruby, Perl, etc.).
What do you think the defining feature of class based inheritance is that allows a clean distinction between JS and Python? Because I don't personally see much of one.
> Because copying feels closer to composition than than it does to OO inheritance or prototype delegation IMO.
Well, opinions are subjective. My experience has been the reverse, however.
Nowhere in the wikipedia main article about inheritance does it cover concatenation inheritance (https://en.wikipedia.org/wiki/Inheritance_(object-oriented_p...). You only find it in the article about Prototype based programming (https://en.wikipedia.org/wiki/Prototype-based_programming). It's also my personal experience (started with Java when it was first released...) that inheritance means class-based inheritance to a lot of devs. I'm sure that changes depending on which devs you hang out with.
If I understand right, concatenation is more commonly called a mixin? At least the way it's done in javascript. In which case the wikipedia article on that says 'Mixins are sometimes described as being "included" rather than "inherited". Mixins encourage code reuse and can be used to avoid the inheritance ambiguity that multiple inheritance can cause'
Based on that last quote, I'm confident I'm not the only one with the opinion that concatenation inheritance isn't a strict "is-a" relationship and might veer towards "has-a". Maybe "has-a-trait" type relationship? That's also how Eric Elliot was using Object.assign. A guitar has distortion, volume, and a cabinet. Let's not go in circles: I still agree his code isn't composition. But mixins sure do blur the lines between composition and inheritance for me.
> That's not a distinguishing feature of class based inheritance
It was an aside. Not very important to the point I was making. The point was that prototype delegation and class inheritance are similar in the way that methods are inherited, and that's different from how concatenation treats methods. But thanks for the info, I didn't know that about Python.
Object.assign({}, { author: author }, { post: post });
Can you give a better example of where a reference to an instance is any different than copying an instance?EDIT: I fixed your example. https://jsbin.com/zamuqoropa/1/edit?js,console
EDIT 2: In fact, my Object.assign does exactly the same thing as your example of composition. And console.log(obj1.author === obj2.author); produces 'true'. https://jsbin.com/vafudizumo/1/edit?js,console Either you're doing composition wrong, or I'm not doing inheritance like you are claiming.
Yes.
> Using composition with Object.assign is far less fragile than inheritance.
Absolutely not. Object.assign is an example of inheritance, not composition, and it's just as fragile as the others. Eric Elliott is well known for calling "composition" what everyone else calls "multiple inheritance". See, eg:
http://wsieroci.github.io/elliott/inheritance/composition/20...
https://www.reddit.com/r/javascript/comments/3oy9c3/composit...
It's almost a running joke on the /r/javascript subreddit at this point.