如何使用函数式编程正确替换“扩展”?

2023-12-11

我正在研究如何在 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/tical-mixins-composition-software-ffb66d5e731c

const 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())

那么问题是,我们如何仅使用函数来优雅地解决这个问题?


preface

OP 正在寻找的可能解决方案背后的机制仍然是 OO,因为 OO 可以是这样的;毕竟,我们正在处理的是通过调用 javascript 函数进行对象组合(或对象/类型增强)。埃里克·埃利奥特 -函数式混合- 和道格拉斯·克罗克福德 -功能继承- 每个人都很好地解释了他们的方法。他们可能错过了命名/标签。在我看来,它应该很简单基于函数的混合。自从这个术语出现以来,JavaScript 开发人员之间的混淆将会减少功能性的不会再指向或误导“FP 之地”.

JavaScript 的强大力量function具有以下功能:第一通过创建闭包保留范围,第二通过this并通过其调用方法之一提供前者call or apply。第三,它本身是一个可以传递的一流对象,使整个包更加完美。

approach

OP 的问题是如何实现一个模块化行为,该行为依赖于由另一个行为封装的状态,可以通过传递此状态来解决。这种状态不一定要公开展示。

埃里克和道格拉斯的概念将得到字面上的尊重/认可applying it.

在我看来,JavaScript 中的模块化可组合行为始终应该由一个函数提供,而两个函数都不应该通过new关键字nor 不应由调用运算符调用...()..,但它始终必须通过以下任一方式应用于其他对象/类型call or 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; }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用函数式编程正确替换“扩展”? 的相关文章

  • 使 Knockout applyBindings 将选择选项视为数字

    我将 Knockout 与 html select option 结合使用 请参阅Fiddle http jsfiddle net hf5gb
  • HTMLPanel 中的 JavaScript

    我想在 HTMLPanel 元素中包含 Javascript 代码 但它不起作用 请你帮助我好吗 提前致谢 脚本 pro js alert hello 使用 HTMLPANEL 不起作用 不显示警报 我认为应该是相反的 HTMLPanel
  • python编写的类爬虫抛出属性错误

    用 python 编写一些代码后 我陷入了深深的麻烦 我是按照 Python 中的 OOP 设计编写代码的新手 我在代码中使用的 xpath 是完美的 当通过 page crawler 类的实例运行 info grabber 类中的 pas
  • 从 HTML 模板调用异步函数(Retunes Observable)

    HTML 模板上显示的数据是关键表单数据 意思是 需要翻译 为此 我想从我的模板中调用异步函数 尝试过这个 但没有成功 模板 span class myClass rowValue translateServingStyle size de
  • 如何使用 jQuery 添加/附加到外部 JSON 文件

    我有一个 json 文件 我想构建一个表单 允许我在文件中添加 编辑元素 是否有 jQuery 函数 方法允许我在外部 json 文件中发布和追加元素 不确定这是否有帮助 但当前的 json 结构如下 cast director genre
  • 如何使用react-native-router-flux在模态中进行导航

    我需要在我的反应本机应用程序中的模式中进行导航 使用新版本的react native router flux 似乎不可能做到这一点 我可以创建一个垂直动画来显示下一个场景 这与场景顶部的模态不同
  • 将全局样式表与故事书和角度结合使用 - SassError:SassError:预期“{”

    几天来 我一直在尝试将全局样式表集成到故事书中 我已经从 sass 支持文档中集成了 webpackFinal 配置 在 storybook 目录中 我创建了一个 scss loader scss 文件 该文件应该加载全局样式表 在 pre
  • 使用 ReactJS 突出显示文本

    我试图突出显示与查询匹配的文本 但我不知道如何让标签显示为 HTML 而不是文本 var Component React createClass highlightQuery function name query var regex ne
  • 关联数组不按顺序排列

    关联数组的顺序是这样的 A00 gt value1 A01 gt value2 B01 gt value3 B02 gt value4 但是在 for 循环之后数组顺序不起作用 for var key in obj3 code list1
  • 隐藏加载失败的图片

    我有一个 Android 应用程序 它生成一些在本地 Webkit 视图中呈现的 HTML HTML 生成的细节实际上并不那么重要 除了 大部分来自一个地方 我无法改变它 HTML 周围的模板 包括页眉 页脚 HEAD 等 CSS 和 Ja
  • 如何向 DOM 添加支持 Angular 的元素?

    我想以编程方式添加一些支持 Angular 的 DOM 元素 实际上 我可能需要添加自定义组件 我该怎么做 这是一个简单的小提琴来演示这个问题 http jsfiddle net ZJSz4 2 http jsfiddle net ZJSz
  • JavaScript 事件循环:队列、消息队列、事件队列

    阅读了大量 JavaScript 事件循环教程 我看到了不同的术语来标识当调用堆栈为空时准备由事件循环获取的队列存储消息 Queue 消息队列 事件队列 我找不到规范术语来识别这一点 甚至 MDN 似乎也对此感到困惑事件循环页面 https
  • 在 Angular 2+ 中进行 DOM 操作的正确方法

    我知道有一些类似的问题 但没有人回答我的问题 基本上 以角度方式操作 DOM 的正确方法是什么 比如说我有这个 html
  • 如何使用 php __toString

    有什么用途 toString in PHP 例如 我有一个函数 例如 在一个名为 person 的类中 public function construct id name this gt id id this gt name name an
  • Mapbox 关闭除一层之外的所有图层

    我是 Mapbox 和 javascript 的新手 我试图稍微修改一下 Mapbox GL 代码示例 发现here https www mapbox com mapbox gl js example toggle layers 允许打开
  • 如何在 Strongloop 环回脚手架项目中覆盖基本用户?

    给定一个使用以下命令创建的全新项目 slc lb project myapp 我该如何更换 user 模型中models json带有 customer 模型放置在 models目录 客户应该有登录 注销等方法 并且 用户 不应该作为 AP
  • 函数声明可以出现在 JavaScript 的语句内部吗?

    请考虑将官方 ECMAScript 规范作为您答案的来源 而不是特定浏览器供应商发布的文档 我知道 Mozilla 用 函数语句 扩展了它的 JavaScript 实现 因此 根据 ECMAScript 规范 因此 其中定义的语法产生式 这
  • Vue js - 在同一级别的两个组件内传递数据

    我有需要从一个传递的数据component1到另一个component2 我不使用vuex or router 组件树 Parent Component1 Component2 从一开始component1我发出 ajax 请求 检索信息并
  • 使用与 eval 相反的括号表示法

    我有以下内容 var module function console log module ran var someString module string TypeError object is not a function eval s
  • 访问 django for 循环中的元素

    我有一个 Django 模板 其中包含以下代码 该模板创建多个按钮并尝试通过单击 在同一按钮上 删除 隐藏其中一个按钮 for h in helicopters div class btn group div

随机推荐