3 ms·
> In both cases you end up with an object that has an instance of an author and a post. But you don't; not even close. The first one is a has-a relationship;
by Lazare 10y ago
> In both cases you end up with an object that has an instance of an author and a post.
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 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. :)
- tchaffee 10y agoI can get foo.author.title and foo.post.title no problem using Object.assign: 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 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 https://jsbin.com/vafudizumo/1/edit?js,console Either you're doing composition wrong, or I'm not doing inheritance like you are claiming.
- Lazare 10y agoObject.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-about-inheritance-in-javascript-d5d9bab29b0a#.jw2f0032r https://medium.com/javascript-scene/common-misconceptions-ab...
- tchaffee 10y agoI agree now that what Eric Elliot is doing is not composition. But it's not inheritance as it is commonly known either. If I inherit from a prototype, then inherited objects can use the prototype methods via prototype delegation. If I change a method in the prototype, inherited objects will see that change. Which is similar to class based inheritance, but can happen at run time. That will not happen with Object.assign because it is cloning or copying. If I make a change to a prototype I cloned from, the cloned object will not be changed. This is also known as concatenative prototyping. Yes, it's considered a type of inheritance, but I think different enough from prototype delegation and class inheritance that it should be pointed out when claiming it is inheritance. Because copying feels closer to composition than than it does to OO inheritance or prototype delegation IMO. Composition still wins though. Good discussion. "By absolutely no one ever. :)" Actually, quite often. A few examples below: https://en.wikipedia.org/wiki/Prototype-based_programming#Concatenation https://en.wikipedia.org/wiki/Prototype-based_programming#Co... http://aaditmshah.github.io/why-prototypal-inheritance-matters/ http://aaditmshah.github.io/why-prototypal-inheritance-matte... http://www.datchley.name/understanding-prototypes-delegation-composition/ http://www.datchley.name/understanding-prototypes-delegation...