0

I've been trying to wrap my head around Object Composition for a while and I can't seem to find the "correct way" to do the same I was doing before with OOP. Lets say I have a class Entity with 3 variables, with OOP I would just create a class Entity and all the children of this class would have these 3 properties, but using object composition I can't seem to understand how I'm supposed to mimic this inheritance.

const Entity = {
    let self = {
         x: 0,
         y: 0,
         z: 0,
}

Do I need to create these properties in all other objects I create that need them? Or is there a better way to reuse these properties?

const ObjectX = {
     let state = {
        x: 0,
        y: 0,
        z: 0,
        abc: 0,
        cba: 0,
return Object.assign(state, canDoX);
}

const ObjectY = {
     let state = {
        x: 0,
        y: 0,
        z: 0,
        foo: 0,
        bar: 0,
return Object.assign(state, canDoY);
}
w1sh
  • 68
  • 9
  • Object literals should not have a return value or a comma at the end of the property list. – StackSlave Oct 12 '18 at 10:06
  • Code that you are showing us won't even compile `const Entity = {}` is literal object declaration and what should follow are key/value pairs, but you have some `let self` statement there which is definitely incorrect and will automatically throw an error. – Matus Dubrava Oct 12 '18 at 10:07
  • `Entity and all the children of this class would have these 3 properties`, in Javascript you would use the protototype, but first you need to create a Class, not an Object.. – Keith Oct 12 '18 at 10:10
  • @Keith creating a class is cool, but it is just syntactic sugar, so I would not say you **need** to create one, but perhaps you **should** create one. I think it's important to understand how the underlying functions and objects work in javascript in order to understand how a Class works in javascript. – Billy Moon Oct 12 '18 at 10:13
  • @MatusDubrava I've been following this [guide](https://medium.com/code-monkey/object-composition-in-javascript-2f9b9077b5e6) so I assumed it was the way to do it. – w1sh Oct 12 '18 at 12:43
  • @BrunoFerreira Well first things first, this isn't object composition. It looks like your guide may have learned from MPJ's videos, but MPJ got composition completely, entirely wrong. https://www.reddit.com/r/programming/comments/5dxq6i/composition_over_inheritance/da8bplv/ – Jeff M Oct 13 '18 at 16:16
  • @BrunoFerreira I just posted a reply to your guide with more detailed information. https://medium.com/@jeffm712/youve-been-misinformed-a96c0d1fb4fe – Jeff M Oct 13 '18 at 16:45
  • @JeffM I will take a look at it, thank you for your contribution. Do you perhaps known of a trustable source for learning Object Composition? – w1sh Oct 15 '18 at 10:15
  • The first and easiest is wikipedia. Composition\_over\_inheritance and Has-a articles describe composition as containing instances and as having a member field of an object. The Python community, the ActionScript community (ActionScript is an ECMAScript language), the C++ community, JavaScript-specific explanations that pre-date the recent spread of misinformation, and most importantly the GoF book -- where the rule favor composition over inheritance comes from -- all describe composition that same way. – Jeff M Oct 16 '18 at 00:53
  • https://en.wikipedia.org/wiki/Composition_over_inheritance - https://en.wikipedia.org/wiki/Has-a - https://web.archive.org/web/20170707220607/https://learnpythonthehardway.org/book/ex44.html - http://www.adobe.com/devnet/actionscript/learning/oop-concepts/composition-and-aggregation.html - http://www.artima.com/cppsource/codestandards3.html - https://stackoverflow.com/a/8696786/1698612 - https://i.imgur.com/xDHUGYc.png – Jeff M Oct 16 '18 at 00:54

2 Answers2

1

If you want to extend (via prototype) some object with another object then you can use Object.create method which takes an object as argument and creates a new object with this passed in object linked to it via prototype chain.

const entity = {
    x: 1,
    y: 2,
    z: 3
};

const objectX = Object.create(entity);
objectX.abc = 'something';

console.log(objectX.x);
console.log(objectX.y);
console.log(objectX.z);
console.log(objectX.abc);

If you just want to mix one object into another then you can use Object.assign and pass an empty object as the first argument and the entity object as the second argument to this method which will then create a new object with all the properties copied from the entity (note that this is only a shallow copy therefore you need to take some special care if that entity contains some other objects inside of it - those will be copied by reference therefore you would mutate the original ones if you would update them).

const entity = {
    x: 1,
    y: 2,
    z: 3
};

const objectX = Object.assign({}, entity);
objectX.abc = 'something';

console.log(objectX.x);
console.log(objectX.y);
console.log(objectX.z);
console.log(objectX.abc);

Last thing, Object.assign can be replaced by object destructuring like this.

const objectX = { ...entity };

But again, this also produces only a shallow copy.

Matus Dubrava
  • 13,637
  • 2
  • 38
  • 54
0

You probably want a constructor?

function BatLoser(batterName){
  this.batter = batterName; this.balls = 0; this.strikes = 0; this.onBase = false; this.strikeOut = false;
  this.swing = function(){
    var zeroOneTwo = Math.floor(Math.random()*3);
    switch(zeroOneTwo){
      case 0:
        this.balls++;
        console.log('ball '+this.balls+' for '+this.batter);
        break;
      case 1:
        this.strikes++;
        console.log('strike '+this.strikes+' for '+this.batter);
        break;
      case 2:
        this.onBase = true;
        console.log(this.batter+' hits the ball and is on base');
        return this;
    }
    if(this.balls > 3){
      this.onBase = true;
      console.log(this.batter+' walks on base');
    }
    if(this.strikes > 2){
      this.strikeOut = true;
      console.log(this.batter+' struck out');
    }
    return this;
  }
  this.batterUp = function(){
    while(!this.onBase && !this.strikeOut){
      this.swing();
    }
    return this;
  }
}
var bob = new BatLoser('Bob'), joe = new BatLoser('Joe');
bob.batterUp(); console.log('-------'); joe.batterUp();

Just keep hitting that button to see how the results vary.

Note that every new instance of a Constructor creates a new Object. Object literals do not have a __constructor method, or whatever you are used to.

StackSlave
  • 10,613
  • 2
  • 18
  • 35