Is it possible to extend only some specific part from multiple classes? Example:
Note ... I had to split my previous answer into 2 separate parts since for quite a while it is not anymore that easy referencing outside hosted javascript code. Due to that I now do provide the necessary trait library as minified inline code within the next given example ...
Having on hand natively implemented Talents or Traits one day in JavaScript, will make this kind of composition even more flexible/powerful ...
var
withWalkingAbility = (function mixinFactory () {
function walking() {
return "walking";
}
return function abilityMixin () {
this.walk = walking;
};
}()),
withRunningAbility = Trait.create(function trait (use, applicator) {
function running() {
return "running";
}
applicator(function () {
this.run = running;
});
});
var
withSelfAwareness = (function mixinFactory () {
function reflectThySelf() {
return "I'm";
}
return function awarenessMixin () {
this.reflect = reflectThySelf;
};
}()),
withDepersonalization = Trait.create(function trait (use, applicator) {
function objectify() {
return "It's";
}
applicator(function () {
this.objectify = objectify;
});
});
var
withSelfAwareWalkingAndRunningAbility = Trait.create(function trait (use, applicator) {
use(withWalkingAbility, withRunningAbility)
.apply.all();
applicator(function () {
this.walk = (function (proceed) {
return function () {
console.log([this.reflect(), proceed.call(this)].join(' '))
};
}(this.walk));
this.run = (function (proceed) {
return function () {
console.log([this.reflect(), proceed.call(this)].join(' '))
};
}(this.run));
}).requires([
"reflect"
]);
}),
withDepersonalizedRunningAbility = Trait.create(function trait (use, applicator) {
use(withRunningAbility)
.apply(withRunningAbility);
applicator(function () {
this.run = (function (proceed) {
return function () {
console.log([this.objectify(), proceed.call(this)].join(' '))
};
}(this.run));
}).requires([
"objectify"
]);
});
class Human {
constructor() {
// `Human` specific instance slots.
}
// `Human` specific prototypal methods.
}
withSelfAwareness.call(Human.prototype);
class Animal {
constructor() {
withDepersonalization.call(this);
// other `Animal` specific instance slots.
}
// `Animal` specific prototypal methods.
}
class HumanWalkerAndRunner extends Human {
constructor() {
super();
}
}
withSelfAwareWalkingAndRunningAbility.call(HumanWalkerAndRunner.prototype);
class AnimalRunner extends Animal {
constructor() {
super();
withDepersonalizedRunningAbility.call(this);
}
}
var
humanWalkerAndRunner = (new HumanWalkerAndRunner),
animalRunner = (new AnimalRunner);
console.log('humanWalkerAndRunner : ', humanWalkerAndRunner); // HumanWalkerAndRunner {}
console.log('(humanWalkerAndRunner instanceof HumanWalkerAndRunner) ? ', (humanWalkerAndRunner instanceof HumanWalkerAndRunner)); // true
console.log('(humanWalkerAndRunner instanceof Human) ? ', (humanWalkerAndRunner instanceof Human)); // true
humanWalkerAndRunner.walk(); // "I'm walking"
humanWalkerAndRunner.run(); // "I'm running"
console.log('(humanWalkerAndRunner.hasOwnProperty("walk")) ? ', humanWalkerAndRunner.hasOwnProperty("walk")); // false
console.log('(humanWalkerAndRunner.hasOwnProperty("run")) ? ', humanWalkerAndRunner.hasOwnProperty("run")); // false
console.log('\n');
console.log('animalRunner : ', animalRunner); // AnimalRunner {objectify: function, run: function}
console.log('(animalRunner instanceof AnimalRunner) ? ', (animalRunner instanceof AnimalRunner)); // true
console.log('(animalRunner instanceof Animal) ? ', (animalRunner instanceof Animal)); // true
animalRunner.run(); // "It's running"
console.log('(animalRunner.hasOwnProperty("run")) ? ', animalRunner.hasOwnProperty("run")); // true
.as-console-wrapper { max-height: 100%!important; top: 0; }