Why “Favor composition over inheritance” and not “Favor aggreggation over inheritance”?

I have read many different articles on “Favor composition over inheritance” over the years and despite reading so many, actually finding clear concise code examples has been difficult.

I understand that all examples will generally be overly simplified, but here are the most common code examples I see across different articles along with my current understanding;

class Animal {
  eat() {...}
  sleep() {...}
}

class Doggo extends Animal { ... }

console.log((new Doggo()).eat())

With inheritance, if we modify the Parent class (Animal), we may subtly affect sub-classes in different ways; Parent methods change which impact the sub-class or many superfluous methods are added to the Parent that the sub-class doesn’t need or the likelihood of mutation is increased from Parent class properties etc.

In time the Parent class becomes bloated or an incorrect abstraction so we need to keep separating the Parent into more sub-classes and inherit from those (i.e. Animal – Dog – Doggo) which incurs it’s own cost.

class Doggo {
  constructor() {
    this.eat = (new Eat()).eat;
    this.sleep = (new Sleep()).sleep;
  }
}

console.log((new Doggo()).eat())

An alternative is composition.

The difference, is that composition involves the class being -composed- of other objects. The benefit being the Doggo class only uses the objects (functions) it really needs.

From my understanding of composition, when the Doggo object is destroyed, the objects it is comprised of (Eat, Sleep) are also destroyed.

I have seen many examples where these objects are instantiated in the class’ constructor, just like above. Maybe I was unlucky to find such examples, but I think you can see where I am going with this;

class Doggo {
  constructor(eat, sleep) {
    this.eat = eat.eat;
    this.sleep = sleep.sleep;
  }
}

let eat = new Eat()
let sleep = new Sleep()
console.log((new Doggo(eat, sleep)).eat())

Analogous to composition, is -aggregation-, where a classes dependencies exist independent of the class. Most often I see this represented as the dependencies being injected (Dependency Injection). In this case, when the Doggo class is destroyed, the Eat and Sleep classes continue to exist (if called again after the Doggo class clean-up).

Now, from a testing point of view, to me, aggregation is clearly the better choice when feasible, since mock dependencies can be injected during testing, while with aggregation, those dependencies are difficult/impossible to mock.

So if my simplified examples are correct, as an alternative to inheritance, why would composition be preferred over aggregation? Or are my examples too simplified and focusing on the wrong take-away?

As an aside, I have also seen examples suggest that “composition over inheritance” is actually about defining many discrete interfaces and having a class implement those instead. I believe there is overlap if you combine the interfaces along with the use of dependency objects, but the use of interfaces alone is more in line with the SOLID Interface Segregation Principle. Would this also be correct to state?