1 回答

TA貢獻1785條經驗 獲得超8個贊
前言
OP 正在尋找的可能解決方案背后的機制仍然是 OO,就像 OO 一樣;畢竟,人們正在處理的是通過調用 javascript 函數進行對象組合(或對象/類型擴充)。Eric Elliott -功能性 mixin - 和 Douglas Crockford -功能性繼承- 每個都很好地解釋了他們的方法。他們可能錯過了命名/標簽。在我看來,它應該像基于函數的 mixin一樣簡單。JavaScript 開發人員之間的混淆會減少,因為函數式術語將不再指向或誤導?The Land of FP?。
JavaScript 的強大功能function來自于它的每一個能力,第一是通過創建閉包來保持范圍,第二是通過它的調用方法之一訪問上下文并this提供前者。在第 3 位,它本身是一個可以傳遞的一流對象,它只是對完整的包進行了四舍五入。callapply
方法
OP 的問題是如何實現模塊化行為,該行為依賴于由另一個行為封裝的狀態,可以通過傳遞此狀態來解決。這種狀態不一定要公開展示。
Eric 和 Douglas 的概念將通過實際應用而得到尊重/認可。
在我看來,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; }
添加回答
舉報