предисловие
Механизм возможного решения, который ищет OP, все еще остается OO, каким может быть OO; в конце концов, то, с чем мы имеем дело, это составление объекта (или увеличение объекта / типа) посредством вызова функций javascript. Eri c Elliott - функциональный миксин - и Дуглас Крокфорд - функциональное наследование - каждый действительно объясняет свой подход довольно хорошо. Они могли пропустить название / маркировку. На мой взгляд, это должно быть так просто, как функция на основе функции mixin . JavaScript разработчиков будет меньше путаницы, поскольку термин функциональный больше не будет указывать или вводить в заблуждение в »The Land of FP« .
Могущественная сила JavaScript function
поставляется с каждой из его способностей, во-первых, сохранять область посредством создания замыканий и, во-вторых, доступа к контексту через this
и предоставления первого посредством одного из его методов вызова call
или apply
. Когда 3-й объект сам по себе является объектом первого класса, который можно обойти, он просто округляет весь пакет.
подхода
Проблема ОП в том, как реализовать модульное поведение, имеющее зависимости, чтобы утверждать, что инкапсулированное другим поведением может быть решено путем передачи этого состояния. Это состояние не обязательно должно быть публично отображено. Концепция
Eri c и Дугласа будет соблюдена / признана буквально , применяя it.
По моему мнению, модульное составное поведение в JavaScript всегда должно обеспечиваться функцией, которая не должна вызываться через ключевое слово new
и не вызываться оператором вызова ... ()
.., но он всегда должен применяться к / на другие объекты / типы с помощью call
или apply
.
Пример кода OP с общим, но защищенным (локально ограниченным) состоянием полета ...
function withFlightStateAlteringFlightCapability(state) {
const flightCapableType = this;
flightCapableType.fly = () => {
state.flying = true;
return flightCapableType;
};
flightCapableType.land = () => {
state.flying = false;
return flightCapableType;
};
flightCapableType.isFlying = () => state.flying;
return flightCapableType;
}
function withFlightStateDependedEggLayingBehavior(state) {
const oviparousType = this;
oviparousType.layEgg = () => {
let returnValue;
// if (!this.isFlying()) {
if (!state.flying) {
returnValue = 'Laying egg...'
}
return returnValue;
};
return oviparousType;
}
function withMetaBehavior(label, behavior) {
this[label] = behavior;
}
class Duck {
constructor() {
// - glue code wrapped by constructor.
// - type will feature a class signature.
// - `state` gets preserved by the closure that is created with each instantiation.
// local state (shared and protected)
const state = {
flying: false
};
const duck = this;
withFlightStateAlteringFlightCapability.call(duck, state);
withFlightStateDependedEggLayingBehavior.call(duck, state);
withMetaBehavior.call(duck, 'quack', () => 'Quaaack...Quaaack...');
}
}
const duck = new Duck;
function createDuckAlikeType() {
// - glue code wrapped by factory function.
// - type will be an augmented but ordinary `Object` type.
// - `state` gets preserved by the closure that is created with each invocation of the factory.
// local state (shared and protected)
const state = {
flying: false
};
const type = {};
withFlightStateAlteringFlightCapability.call(type, state);
withFlightStateDependedEggLayingBehavior.call(type, state);
withMetaBehavior.call(type, 'quack', () => 'Quack!');
return type;
}
const duckAlikeType = createDuckAlikeType();
console.log('composed "real duck" : ', duck);
console.log('composed "duck alike type" : ', duckAlikeType);
console.log('\nduck.fly() ...');
duck.fly();
console.log('\nduck.isFlying() ? ', duck.isFlying());
console.log('duckAlikeType.isFlying() ? ', duckAlikeType.isFlying());
console.log('\nduck.layEgg() ? ', duck.layEgg());
console.log('duckAlikeType.layEgg() ? ', duckAlikeType.layEgg());
console.log('\nduck.land().layEgg() ? ', duck.land().layEgg());
console.log('duckAlikeType.fly().layEgg() ? ', duckAlikeType.fly().layEgg());
console.log('\nduck.isFlying() ? ', duck.isFlying());
console.log('duckAlikeType.isFlying() ? ', duckAlikeType.isFlying());
console.log('\nduck.quack() ? ', duck.quack());
console.log('duckAlikeType.quack() ? ', duckAlikeType.quack());
.as-console-wrapper { max-height: 100%!important; top: 0; }