JS/TS: 我怎样才能把一个工厂函数变成一个更实用的模式?

JS/TS: How can I turn a factory function into a more functional pattern?

我已将 class 重构到一个模块中,其中每个函数都需要辅助函数才能工作。

OO Class

class Foo {
  constructor(config) {
    this.helper = new Helper(config);
  }

  fooMethod (arg) {
    return this.helper(arg);
  }
}

工厂方法

const fooFN = (helper) => (arg) => helper(arg);

export default Foo (config) => {
  const helper = new Helper(config);

  return {
     fooMethod: fooFN(helper)
  }
}

这个辅助函数是在工厂函数中初始化的,returns所有需要辅助方法的函数的一部分。

IMO 这不是路的尽头。与 class 的区别很小,可能还有另一种更实用的方法来编写它,但我无法理解它。

如何将辅助函数传递给模块的每个导出成员,而无需在每次调用成员时都初始化辅助函数?

考虑您的面向对象代码。

class Foo {
  constructor(config) {
    this.helper = new Helper(config);
  }

  fooMethod (arg) {
    return this.helper(arg);
  }
}

以下是我将其重构为函数式风格的方法。

const Foo = helper => ({ helper }); // constructor

const fooFunction = (foo, arg) => foo.helper(arg); // fooMethod

您将按如下方式使用它。

const foo = Foo(Helper(config)); // new Foo(config)

fooFunction(foo, arg); // foo.fooMethod(arg);

如您所见,代码更加简洁。此外,它更简单,因为您不使用 thisnew.


编辑: 如果您担心导入太多东西,那么您可以使用命名空间导入。

import { Helper } from "./helper";

export const Foo = helper => ({ helper }); // data constructor

export const Foo2 = config => Foo(Helper(config)); // constructor

export const fooFunction = (foo, arg) => foo.helper(arg); // fooMethod

您将按如下方式使用它。

import * as F from "./foo";

const foo = F.Foo2(config); // new Foo(config)

F.fooFunction(foo, arg); // foo.fooMethod(arg);

引用 Zen of Python,“命名空间是一个很棒的想法——让我们做更多!”

我看不出有什么理由要从您的对象中删除 .helper 属性。你可以只写

function fooMethod(arg) {
  return this.helper(arg);
}

export default function(config) {
  return {
     helper: Helper(config),
     fooMethod,
  }
}

这样 fooMethod 被重用,就像 class 语法一样。

我宁愿利用组合并完全避免任何 class。

  1. 它不一定是 class,因为它实际上并不依赖于任何内部状态或上下文。
  2. 我们知道 fn 除非提供 helper 依赖项,否则无法使用。

function Helper(config) {

  return (...args) => console.log({ config, args });
}

const withHelper = (helper) => (...args) => helper(...args);

const foo = withHelper(new Helper({ name: 'foo' }));
const baz = withHelper(new Helper({ name: 'baz' }));

foo(1, 2, 3, 4);
baz('Hello', 'World');