亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何使用函數式編程正確替換“擴展”?

如何使用函數式編程正確替換“擴展”?

catspeake 2022-06-16 14:37:52
我正在研究如何在 javascript 中應用函數式編程,并且正在嘗試避免使用class關鍵字。我不喜歡僅僅為了遵循某種范式而采取極端措施,但我很想知道是否可以在不使用類的情況下編寫好的代碼。到目前為止,我主要使用函數取得了成功,但有一種情況我無法真正弄清楚。當我們有想要在不同對象之間重用的行為時,我們通常(在 OOP 中)創建一個擴展另一個類的類。class FlyingThing {   private let _isFlying = false   fly() {       _isFlying = true       return this   }   land() {       _isFlying = false       return this   }   isFlying() {      return _isFlying   }}class Duck extends FlyingThing {   quack() {       return 'Quack!'   } }const duck = new Duck()console.log(duck.fly().quack())現在到功能方法...示例取自:https ://medium.com/javascript-scene/functional-mixins-composing-software-ffb66d5e731cconst flying = o => {  let isFlying = false  return Object.assign({}, o, {    fly () {      isFlying = true      return this    },    isFlying: () => isFlying,    land () {      isFlying = false      return this    }  })}const quacking = quack => o => Object.assign({}, o, {  quack: () => quack})const createDuck = quack => quacking(quack)(flying({}))const duck = createDuck('Quack!')console.log(duck.fly().quack())好的,我喜歡這個主意;我們正在使用組合,并且我們沒有任何父母和孩子之間的緊密耦合。涼爽的。但是,通常當我們使用類時,子級可以訪問父級的成員,并且可能需要在某些方法中使用它。例如:class FlyingThing {   private let _isFlying = false   fly() {       _isFlying = true       return this   }   land() {       _isFlying = false       return this   }   isFlying() {      return _isFlying   }}class Duck extends FlyingThing {   quack() {       return 'Quack!'   }   // New method - Depends on 'isFlying' defined in parent   layEgg() {       if(isFlying) return       return 'Laying egg...'   }}const duck = new Duck()console.log(duck.fly().quack())所以問題是,我們如何僅使用函數優雅地解決這個問題?
查看完整描述

1 回答

?
慕的地10843

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; }


查看完整回答
反對 回復 2022-06-16
  • 1 回答
  • 0 關注
  • 149 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號